mirror of https://github.com/ThmmyNoLife/mTHMMY
29 changed files with 1627 additions and 54 deletions
@ -1,26 +0,0 @@ |
|||||
package gr.thmmy.mthmmy; |
|
||||
|
|
||||
import android.content.Context; |
|
||||
import android.support.test.InstrumentationRegistry; |
|
||||
import android.support.test.runner.AndroidJUnit4; |
|
||||
|
|
||||
import org.junit.Test; |
|
||||
import org.junit.runner.RunWith; |
|
||||
|
|
||||
import static org.junit.Assert.*; |
|
||||
|
|
||||
/** |
|
||||
* Instrumentation test, which will execute on an Android device. |
|
||||
* |
|
||||
* @see <a href="http://d.android.com/tools/testing">Testing documentation</a> |
|
||||
*/ |
|
||||
@RunWith(AndroidJUnit4.class) |
|
||||
public class ExampleInstrumentedTest { |
|
||||
@Test |
|
||||
public void useAppContext() throws Exception { |
|
||||
// Context of the app under test.
|
|
||||
Context appContext = InstrumentationRegistry.getTargetContext(); |
|
||||
|
|
||||
assertEquals("gr.thmmy.mthmmy", appContext.getPackageName()); |
|
||||
} |
|
||||
} |
|
@ -1,13 +1,44 @@ |
|||||
|
<?xml version="1.0" encoding="utf-8"?> |
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android" |
<manifest xmlns:android="http://schemas.android.com/apk/res/android" |
||||
package="gr.thmmy.mthmmy"> |
package="gr.thmmy.mthmmy"> |
||||
|
|
||||
|
<uses-permission android:name="android.permission.INTERNET" /> |
||||
|
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> |
||||
|
|
||||
<application |
<application |
||||
android:allowBackup="true" |
android:allowBackup="true" |
||||
android:icon="@mipmap/ic_launcher" |
android:icon="@mipmap/ic_launcher" |
||||
android:label="@string/app_name" |
android:label="@string/app_name" |
||||
android:supportsRtl="true" |
android:supportsRtl="true" |
||||
android:theme="@style/AppTheme"> |
android:theme="@style/AppTheme"> |
||||
|
<activity |
||||
|
android:name=".activities.MainActivity" |
||||
|
android:configChanges="orientation|screenSize" |
||||
|
android:label="@string/app_name" |
||||
|
android:launchMode="singleTop" |
||||
|
android:theme="@style/AppTheme.NoActionBar"> |
||||
|
<intent-filter> |
||||
|
<action android:name="android.intent.action.MAIN" /> |
||||
|
|
||||
|
<category android:name="android.intent.category.LAUNCHER" /> |
||||
|
</intent-filter> |
||||
|
</activity> |
||||
|
<activity |
||||
|
android:name=".activities.AboutActivity" |
||||
|
android:parentActivityName=".activities.MainActivity"> |
||||
|
<meta-data |
||||
|
android:name="android.support.PARENT_ACTIVITY" |
||||
|
android:value=".activities.MainActivity" /> |
||||
|
</activity> |
||||
|
<activity |
||||
|
android:name=".activities.TopicActivity" |
||||
|
android:configChanges="orientation|screenSize" |
||||
|
android:parentActivityName=".activities.MainActivity"> |
||||
|
<meta-data |
||||
|
android:name="android.support.PARENT_ACTIVITY" |
||||
|
android:value=".activities.MainActivity" /> |
||||
|
</activity> |
||||
|
<activity android:name=".activities.BaseActivity"></activity> |
||||
</application> |
</application> |
||||
|
|
||||
</manifest> |
</manifest> |
@ -0,0 +1,23 @@ |
|||||
|
package gr.thmmy.mthmmy.activities; |
||||
|
|
||||
|
import android.os.Bundle; |
||||
|
import android.support.v7.app.AppCompatActivity; |
||||
|
import android.widget.TextView; |
||||
|
|
||||
|
import gr.thmmy.mthmmy.BuildConfig; |
||||
|
import gr.thmmy.mthmmy.R; |
||||
|
|
||||
|
public class AboutActivity extends BaseActivity { |
||||
|
|
||||
|
@Override |
||||
|
protected void onCreate(Bundle savedInstanceState) { |
||||
|
super.onCreate(savedInstanceState); |
||||
|
setContentView(R.layout.activity_about); |
||||
|
String versionName = BuildConfig.VERSION_NAME; |
||||
|
TextView tv= (TextView) findViewById(R.id.version); |
||||
|
if(tv!=null) |
||||
|
tv.setText(getString(R.string.version, versionName)); |
||||
|
|
||||
|
//TODO: add licenses
|
||||
|
} |
||||
|
} |
@ -0,0 +1,39 @@ |
|||||
|
package gr.thmmy.mthmmy.activities; |
||||
|
|
||||
|
import android.support.v7.app.AppCompatActivity; |
||||
|
import android.os.Bundle; |
||||
|
|
||||
|
import com.franmontiel.persistentcookiejar.PersistentCookieJar; |
||||
|
import com.franmontiel.persistentcookiejar.cache.SetCookieCache; |
||||
|
import com.franmontiel.persistentcookiejar.persistence.SharedPrefsCookiePersistor; |
||||
|
|
||||
|
import okhttp3.CookieJar; |
||||
|
|
||||
|
public class BaseActivity extends AppCompatActivity { |
||||
|
|
||||
|
private static boolean cookiesInit=false; //To initialize cookie stuff only once per app start
|
||||
|
protected static CookieJar cookieJar; |
||||
|
protected static SharedPrefsCookiePersistor sharedPrefsCookiePersistor; |
||||
|
|
||||
|
@Override |
||||
|
protected void onCreate(Bundle savedInstanceState) { |
||||
|
super.onCreate(savedInstanceState); |
||||
|
|
||||
|
if(!cookiesInit) |
||||
|
{ |
||||
|
sharedPrefsCookiePersistor = new SharedPrefsCookiePersistor(BaseActivity.this); |
||||
|
cookieJar = new PersistentCookieJar(new SetCookieCache(), sharedPrefsCookiePersistor); |
||||
|
cookiesInit=true; |
||||
|
} |
||||
|
|
||||
|
} |
||||
|
|
||||
|
public static CookieJar getCookieJar() |
||||
|
{ |
||||
|
return cookieJar; |
||||
|
} |
||||
|
|
||||
|
public static SharedPrefsCookiePersistor getSharedPrefsCookiePersistor() { |
||||
|
return sharedPrefsCookiePersistor; |
||||
|
} |
||||
|
} |
@ -0,0 +1,115 @@ |
|||||
|
package gr.thmmy.mthmmy.activities; |
||||
|
|
||||
|
import android.content.Intent; |
||||
|
import android.os.Bundle; |
||||
|
import android.support.design.widget.TabLayout; |
||||
|
import android.support.v4.app.Fragment; |
||||
|
import android.support.v4.app.FragmentManager; |
||||
|
import android.support.v4.app.FragmentPagerAdapter; |
||||
|
import android.support.v4.view.ViewPager; |
||||
|
import android.support.v7.app.AppCompatActivity; |
||||
|
import android.support.v7.widget.Toolbar; |
||||
|
import android.view.Menu; |
||||
|
import android.view.MenuItem; |
||||
|
|
||||
|
import gr.thmmy.mthmmy.R; |
||||
|
import gr.thmmy.mthmmy.data.TopicSummary; |
||||
|
import gr.thmmy.mthmmy.sections.recent.RecentFragment; |
||||
|
|
||||
|
public class MainActivity extends BaseActivity implements RecentFragment.OnListFragmentInteractionListener |
||||
|
{ |
||||
|
private SectionsPagerAdapter mSectionsPagerAdapter; |
||||
|
private ViewPager mViewPager; /** The {@link ViewPager} that will host the section contents.*/ |
||||
|
|
||||
|
@Override |
||||
|
protected void onCreate(Bundle savedInstanceState) { |
||||
|
super.onCreate(savedInstanceState); |
||||
|
setContentView(R.layout.activity_main); |
||||
|
|
||||
|
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar); |
||||
|
setSupportActionBar(toolbar); |
||||
|
|
||||
|
// Create the adapter that will return a fragment for each section of the activity
|
||||
|
mSectionsPagerAdapter = new SectionsPagerAdapter(getSupportFragmentManager()); |
||||
|
|
||||
|
// Set up the ViewPager with the sections adapter.
|
||||
|
mViewPager = (ViewPager) findViewById(R.id.container); |
||||
|
mViewPager.setAdapter(mSectionsPagerAdapter); |
||||
|
|
||||
|
TabLayout tabLayout = (TabLayout) findViewById(R.id.tabs); |
||||
|
tabLayout.setupWithViewPager(mViewPager); |
||||
|
|
||||
|
//TODO: Drawer
|
||||
|
// new DrawerBuilder().withActivity(this)
|
||||
|
// .withToolbar(toolbar)
|
||||
|
// .build();
|
||||
|
|
||||
|
} |
||||
|
|
||||
|
|
||||
|
@Override |
||||
|
public boolean onCreateOptionsMenu(Menu menu) { |
||||
|
// Inflate the menu; this adds items to the action bar if it is present.
|
||||
|
getMenuInflater().inflate(R.menu.menu_main, menu); |
||||
|
return true; |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public boolean onOptionsItemSelected(MenuItem item) |
||||
|
{ |
||||
|
int id = item.getItemId(); |
||||
|
|
||||
|
if (id == R.id.action_about) { |
||||
|
Intent i = new Intent(MainActivity.this, AboutActivity.class); |
||||
|
startActivity(i); |
||||
|
return true; |
||||
|
} |
||||
|
|
||||
|
return super.onOptionsItemSelected(item); |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public void onFragmentInteraction(TopicSummary topicSummary) |
||||
|
{ |
||||
|
Intent i = new Intent(MainActivity.this, TopicActivity.class); |
||||
|
i.putExtra("TOPIC_URL", topicSummary.getTopicUrl()); |
||||
|
i.putExtra("TOPIC_TITLE", topicSummary.getTitle()); |
||||
|
startActivity(i); |
||||
|
} |
||||
|
|
||||
|
//---------------------------------FragmentPagerAdapter---------------------------------------------
|
||||
|
/** |
||||
|
* A {@link FragmentPagerAdapter} that returns a fragment corresponding to |
||||
|
* one of the sections/tabs/pages. If it becomes too memory intensive, |
||||
|
* it may be best to switch to a |
||||
|
* {@link android.support.v4.app.FragmentStatePagerAdapter}. |
||||
|
*/ |
||||
|
public class SectionsPagerAdapter extends FragmentPagerAdapter { |
||||
|
|
||||
|
SectionsPagerAdapter(FragmentManager fm) { |
||||
|
super(fm); |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public Fragment getItem(int position) { |
||||
|
// getItem is called to instantiate the fragment for the given page.
|
||||
|
// Return a PlaceholderFragment (defined as a static inner class below).
|
||||
|
return RecentFragment.newInstance(position + 1); |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public int getCount() { |
||||
|
// Show 1 total pages.
|
||||
|
return 1; |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public CharSequence getPageTitle(int position) { |
||||
|
switch (position) { |
||||
|
case 0: |
||||
|
return "RECENT"; |
||||
|
} |
||||
|
return null; |
||||
|
} |
||||
|
} |
||||
|
} |
@ -0,0 +1,181 @@ |
|||||
|
package gr.thmmy.mthmmy.activities; |
||||
|
|
||||
|
import android.os.AsyncTask; |
||||
|
import android.os.Bundle; |
||||
|
import android.support.v7.app.ActionBar; |
||||
|
import android.support.v7.app.AppCompatActivity; |
||||
|
import android.support.v7.widget.LinearLayoutManager; |
||||
|
import android.support.v7.widget.RecyclerView; |
||||
|
import android.util.Log; |
||||
|
import android.view.LayoutInflater; |
||||
|
import android.view.View; |
||||
|
import android.view.ViewGroup; |
||||
|
import android.webkit.WebView; |
||||
|
import android.widget.ProgressBar; |
||||
|
import android.widget.TextView; |
||||
|
|
||||
|
import gr.thmmy.mthmmy.R; |
||||
|
import gr.thmmy.mthmmy.data.Post; |
||||
|
import gr.thmmy.mthmmy.utils.CustomRecyclerView; |
||||
|
|
||||
|
import org.jsoup.Jsoup; |
||||
|
import org.jsoup.nodes.Document; |
||||
|
|
||||
|
import java.util.ArrayList; |
||||
|
import java.util.List; |
||||
|
|
||||
|
import javax.net.ssl.SSLHandshakeException; |
||||
|
|
||||
|
import okhttp3.OkHttpClient; |
||||
|
import okhttp3.Request; |
||||
|
import okhttp3.Response; |
||||
|
|
||||
|
public class TopicActivity extends BaseActivity { |
||||
|
|
||||
|
private CustomRecyclerView recyclerView; |
||||
|
private TopicAdapter topicAdapter; |
||||
|
private ProgressBar progressBar; |
||||
|
private OkHttpClient client; |
||||
|
|
||||
|
private List<Post> postsList; |
||||
|
|
||||
|
@Override |
||||
|
protected void onCreate(Bundle savedInstanceState) { |
||||
|
super.onCreate(savedInstanceState); |
||||
|
setContentView(R.layout.activity_topic); |
||||
|
|
||||
|
progressBar = (ProgressBar) findViewById(R.id.progressBar); |
||||
|
|
||||
|
|
||||
|
Bundle extras = getIntent().getExtras(); |
||||
|
ActionBar actionbar = getSupportActionBar(); |
||||
|
if(actionbar!=null) |
||||
|
actionbar.setTitle(extras.getString("TOPIC_TITLE")); |
||||
|
|
||||
|
postsList = new ArrayList<>(); |
||||
|
|
||||
|
topicAdapter = new TopicAdapter(); |
||||
|
|
||||
|
recyclerView = (CustomRecyclerView) findViewById(R.id.list); |
||||
|
recyclerView.setLayoutManager(new LinearLayoutManager(findViewById(R.id.list).getContext())); |
||||
|
recyclerView.setAdapter(topicAdapter); |
||||
|
|
||||
|
client = new OkHttpClient.Builder().build(); |
||||
|
new TopicTask().execute(extras.getString("TOPIC_URL")); |
||||
|
|
||||
|
} |
||||
|
|
||||
|
|
||||
|
private class TopicAdapter extends RecyclerView.Adapter<TopicAdapter.ViewHolder> |
||||
|
{ |
||||
|
@Override |
||||
|
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { |
||||
|
View view = LayoutInflater.from(parent.getContext()) |
||||
|
.inflate(R.layout.activity_topic_post_row, parent, false); |
||||
|
return new ViewHolder(view); |
||||
|
} |
||||
|
|
||||
|
|
||||
|
|
||||
|
@Override |
||||
|
public void onBindViewHolder(final ViewHolder holder, final int position) { |
||||
|
|
||||
|
holder.mAuthorView.setText(postsList.get(position).getAuthor()); |
||||
|
holder.mDateTimeView.setText(postsList.get(position).getDateTime()); |
||||
|
holder.mContentView.loadData(postsList.get(position).getContent(), "text/html", null); |
||||
|
|
||||
|
// holder.topic = recentList.get(position);
|
||||
|
//
|
||||
|
// holder.mView.setOnClickListener(new View.OnClickListener() {
|
||||
|
// @Override
|
||||
|
// public void onClick(View v) {
|
||||
|
//
|
||||
|
// 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); //?
|
||||
|
//
|
||||
|
// }
|
||||
|
//
|
||||
|
// }
|
||||
|
// });
|
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public int getItemCount() { |
||||
|
return postsList.size(); |
||||
|
} |
||||
|
|
||||
|
public class ViewHolder extends RecyclerView.ViewHolder { |
||||
|
public final View mView; |
||||
|
public final TextView mAuthorView; |
||||
|
public final WebView mContentView; |
||||
|
public final TextView mDateTimeView; |
||||
|
|
||||
|
public ViewHolder(View view) { |
||||
|
super(view); |
||||
|
mView = view; |
||||
|
mAuthorView = (TextView) view.findViewById(R.id.author); |
||||
|
mContentView = (WebView) view.findViewById(R.id.content); |
||||
|
mDateTimeView = (TextView) view.findViewById(R.id.dateTime); |
||||
|
} |
||||
|
|
||||
|
} |
||||
|
} |
||||
|
|
||||
|
|
||||
|
|
||||
|
//---------------------------------------TOPIC ASYNC TASK-------------------------------------------
|
||||
|
|
||||
|
public class TopicTask extends AsyncTask<String, Void, Boolean> |
||||
|
{ |
||||
|
private static final String TAG="TopicTask"; |
||||
|
private String pageLink; |
||||
|
|
||||
|
private Document document; |
||||
|
|
||||
|
|
||||
|
protected void onPreExecute() { |
||||
|
progressBar.setVisibility(ProgressBar.VISIBLE); |
||||
|
} |
||||
|
|
||||
|
protected Boolean doInBackground(String... strings) |
||||
|
{ |
||||
|
pageLink = strings[0]; |
||||
|
|
||||
|
Request request = new Request.Builder() |
||||
|
.url(pageLink) |
||||
|
.build(); |
||||
|
|
||||
|
try { |
||||
|
Response response = client.newCall(request).execute(); |
||||
|
document = Jsoup.parse(response.body().string()); |
||||
|
return parse(document); |
||||
|
} catch (SSLHandshakeException e) { |
||||
|
Log.w(TAG, "Certificate problem (please switch to unsafe connection)."); |
||||
|
return false; |
||||
|
|
||||
|
} catch (Exception e) { |
||||
|
Log.e("TAG", "ERROR", e); |
||||
|
return false; |
||||
|
} |
||||
|
|
||||
|
} |
||||
|
|
||||
|
|
||||
|
|
||||
|
protected void onPostExecute(Boolean result) |
||||
|
{ |
||||
|
progressBar.setVisibility(ProgressBar.INVISIBLE); |
||||
|
topicAdapter.notifyDataSetChanged(); |
||||
|
} |
||||
|
|
||||
|
private boolean parse(Document document) |
||||
|
{ |
||||
|
return true; |
||||
|
|
||||
|
} |
||||
|
|
||||
|
|
||||
|
} |
||||
|
} |
@ -0,0 +1,29 @@ |
|||||
|
package gr.thmmy.mthmmy.data; |
||||
|
|
||||
|
/** |
||||
|
* Created by ezero on 14/9/2016. |
||||
|
*/ |
||||
|
public class Post |
||||
|
{ |
||||
|
private final String author; |
||||
|
private final String dateTime; |
||||
|
private String content; |
||||
|
|
||||
|
public Post(String author, String dateTime, String content) { |
||||
|
this.author = author; |
||||
|
this.dateTime = dateTime; |
||||
|
this.content = content; |
||||
|
} |
||||
|
|
||||
|
public String getContent() { |
||||
|
return content; |
||||
|
} |
||||
|
|
||||
|
public String getAuthor() { |
||||
|
return author; |
||||
|
} |
||||
|
|
||||
|
public String getDateTime() { |
||||
|
return dateTime; |
||||
|
} |
||||
|
} |
@ -0,0 +1,31 @@ |
|||||
|
package gr.thmmy.mthmmy.data; |
||||
|
|
||||
|
public class TopicSummary |
||||
|
{ |
||||
|
private final String topicUrl; |
||||
|
private final String title; |
||||
|
private final String lastUser; |
||||
|
private final String dateTimeModified; |
||||
|
|
||||
|
|
||||
|
public TopicSummary(String topicUrl, String title, String lastUser, String dateTimeModified) |
||||
|
{ |
||||
|
this.topicUrl = topicUrl; |
||||
|
this.title = title; |
||||
|
this.lastUser = lastUser; |
||||
|
this.dateTimeModified = dateTimeModified; |
||||
|
} |
||||
|
|
||||
|
public String getTopicUrl() { return topicUrl; } |
||||
|
public String getTitle() { |
||||
|
return title; |
||||
|
} |
||||
|
|
||||
|
public String getLastUser() { |
||||
|
return lastUser; |
||||
|
} |
||||
|
|
||||
|
public String getDateTimeModified() { |
||||
|
return dateTimeModified; |
||||
|
} |
||||
|
} |
@ -0,0 +1,88 @@ |
|||||
|
package gr.thmmy.mthmmy.sections.recent; |
||||
|
|
||||
|
import android.support.v7.widget.RecyclerView; |
||||
|
import android.view.LayoutInflater; |
||||
|
import android.view.View; |
||||
|
import android.view.ViewGroup; |
||||
|
import android.widget.TextView; |
||||
|
|
||||
|
import gr.thmmy.mthmmy.R; |
||||
|
import gr.thmmy.mthmmy.data.TopicSummary; |
||||
|
|
||||
|
import java.util.List; |
||||
|
|
||||
|
|
||||
|
/** |
||||
|
* {@link RecyclerView.Adapter} that can display a {@link TopicSummary} and makes a call to the |
||||
|
* specified {@link RecentFragment.OnListFragmentInteractionListener}. |
||||
|
*/ |
||||
|
public class RecentAdapter extends RecyclerView.Adapter<RecentAdapter.ViewHolder> |
||||
|
{ |
||||
|
private final List<TopicSummary> recentList; |
||||
|
private final RecentFragment.OnListFragmentInteractionListener mListener; |
||||
|
|
||||
|
public RecentAdapter(List<TopicSummary> topicSummaryList, RecentFragment.OnListFragmentInteractionListener listener) { |
||||
|
this.recentList = topicSummaryList; |
||||
|
mListener = listener; |
||||
|
} |
||||
|
|
||||
|
|
||||
|
@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); |
||||
|
} |
||||
|
|
||||
|
|
||||
|
|
||||
|
@Override |
||||
|
public void onBindViewHolder(final ViewHolder holder, final int position) { |
||||
|
|
||||
|
holder.mTitleView.setText(recentList.get(position).getTitle()); |
||||
|
holder.mDateTimeView.setText(recentList.get(position).getDateTimeModified()); |
||||
|
holder.mUserView.setText("by " + recentList.get(position).getLastUser()); |
||||
|
|
||||
|
holder.topic = recentList.get(position); |
||||
|
|
||||
|
holder.mView.setOnClickListener(new View.OnClickListener() { |
||||
|
@Override |
||||
|
public void onClick(View v) { |
||||
|
|
||||
|
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); //?
|
||||
|
|
||||
|
} |
||||
|
|
||||
|
} |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public int getItemCount() { |
||||
|
return recentList.size(); |
||||
|
} |
||||
|
|
||||
|
public class ViewHolder extends RecyclerView.ViewHolder { |
||||
|
public final View mView; |
||||
|
public final TextView mTitleView; |
||||
|
public final TextView mUserView; |
||||
|
public final TextView mDateTimeView; |
||||
|
public TopicSummary topic; |
||||
|
|
||||
|
public 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); |
||||
|
} |
||||
|
|
||||
|
// @Override
|
||||
|
// public String toString() {
|
||||
|
// return super.toString() + " '" + mContentView.getText() + "'";
|
||||
|
// }
|
||||
|
} |
||||
|
} |
@ -0,0 +1,363 @@ |
|||||
|
package gr.thmmy.mthmmy.sections.recent; |
||||
|
|
||||
|
import android.content.Context; |
||||
|
import android.os.AsyncTask; |
||||
|
import android.os.Bundle; |
||||
|
import android.support.v4.app.Fragment; |
||||
|
import android.support.v4.widget.SwipeRefreshLayout; |
||||
|
import android.support.v7.widget.LinearLayoutManager; |
||||
|
import android.util.Log; |
||||
|
import android.view.LayoutInflater; |
||||
|
import android.view.View; |
||||
|
import android.view.ViewGroup; |
||||
|
import android.widget.ProgressBar; |
||||
|
import android.widget.RelativeLayout; |
||||
|
import android.widget.Toast; |
||||
|
|
||||
|
import gr.thmmy.mthmmy.R; |
||||
|
import gr.thmmy.mthmmy.data.TopicSummary; |
||||
|
import gr.thmmy.mthmmy.utils.CustomRecyclerView; |
||||
|
|
||||
|
import org.jsoup.Jsoup; |
||||
|
import org.jsoup.nodes.Document; |
||||
|
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 okhttp3.OkHttpClient; |
||||
|
import okhttp3.Request; |
||||
|
import okhttp3.Response; |
||||
|
|
||||
|
/** |
||||
|
* A simple {@link Fragment} subclass. |
||||
|
* Activities that contain this fragment must implement the |
||||
|
* {@link RecentFragment.OnListFragmentInteractionListener} interface |
||||
|
* to handle interaction events. |
||||
|
* Use the {@link RecentFragment#newInstance} factory method to |
||||
|
* create an instance of this fragment. |
||||
|
*/ |
||||
|
public class RecentFragment extends Fragment |
||||
|
{ |
||||
|
private static final String TAG = "RecentFragment"; |
||||
|
// Fragment initialization parameters, e.g. ARG_SECTION_NUMBER
|
||||
|
private static final String ARG_SECTION_NUMBER = "SectionNumber"; |
||||
|
private int sectionNumber; |
||||
|
|
||||
|
private ProgressBar progressBar; |
||||
|
private SwipeRefreshLayout swipeRefreshLayout; |
||||
|
private CustomRecyclerView recyclerView; |
||||
|
private RecentAdapter recentAdapter; |
||||
|
|
||||
|
private List<TopicSummary> topicSummaries; |
||||
|
|
||||
|
private OnListFragmentInteractionListener mListener; |
||||
|
|
||||
|
OkHttpClient client; |
||||
|
|
||||
|
// Required empty public constructor
|
||||
|
public RecentFragment() {} |
||||
|
|
||||
|
/** |
||||
|
* Use ONLY this factory method to create a new instance of |
||||
|
* this fragment using the provided parameters. |
||||
|
* |
||||
|
* @param sectionNumber |
||||
|
* @return A new instance of fragment Recent. |
||||
|
*/ |
||||
|
public static RecentFragment newInstance(int sectionNumber) |
||||
|
{ |
||||
|
RecentFragment fragment = new RecentFragment(); |
||||
|
Bundle args = new Bundle(); |
||||
|
args.putInt(ARG_SECTION_NUMBER, sectionNumber); |
||||
|
fragment.setArguments(args); |
||||
|
return fragment; |
||||
|
} |
||||
|
|
||||
|
public int getSectionNumber() { |
||||
|
return sectionNumber; |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public void onCreate(Bundle savedInstanceState) |
||||
|
{ |
||||
|
super.onCreate(savedInstanceState); |
||||
|
|
||||
|
sectionNumber = getArguments().getInt(ARG_SECTION_NUMBER); |
||||
|
|
||||
|
client = new OkHttpClient.Builder().build(); |
||||
|
|
||||
|
|
||||
|
topicSummaries = new ArrayList<>(); |
||||
|
|
||||
|
|
||||
|
if(sectionNumber==1) //?
|
||||
|
Log.d(TAG,"onCreate"); |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public void onActivityCreated(Bundle savedInstanceState) |
||||
|
{ |
||||
|
super.onActivityCreated(savedInstanceState); |
||||
|
if(sectionNumber==1)//temp
|
||||
|
{ |
||||
|
if(topicSummaries.isEmpty()) |
||||
|
new RecentTask().execute(); |
||||
|
|
||||
|
|
||||
|
} |
||||
|
Log.d(TAG,"onActivityCreated"); |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public void onStart() { |
||||
|
super.onStart(); |
||||
|
if(sectionNumber==1) |
||||
|
Log.d(TAG,"onStart"); |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public void onResume() { |
||||
|
super.onResume(); |
||||
|
if(sectionNumber==1) |
||||
|
Log.d(TAG,"onResume"); |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public void onPause() { |
||||
|
super.onPause(); |
||||
|
if(sectionNumber==1) |
||||
|
Log.d(TAG,"onPause"); |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public void onStop() { |
||||
|
super.onStop(); |
||||
|
if(sectionNumber==1) |
||||
|
Log.d(TAG,"onStop"); |
||||
|
} |
||||
|
|
||||
|
|
||||
|
@Override |
||||
|
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); |
||||
|
|
||||
|
// Set the adapter
|
||||
|
if (rootView instanceof RelativeLayout) |
||||
|
{ |
||||
|
progressBar = (ProgressBar) rootView.findViewById(R.id.progressBar); |
||||
|
recentAdapter = new RecentAdapter(topicSummaries, mListener); |
||||
|
|
||||
|
recyclerView = (CustomRecyclerView) rootView.findViewById(R.id.list); |
||||
|
recyclerView.setLayoutManager(new LinearLayoutManager(rootView.findViewById(R.id.list).getContext())); |
||||
|
recyclerView.setAdapter(recentAdapter); |
||||
|
|
||||
|
swipeRefreshLayout = (SwipeRefreshLayout) rootView.findViewById(R.id.swiperefresh); |
||||
|
swipeRefreshLayout.setOnRefreshListener( |
||||
|
new SwipeRefreshLayout.OnRefreshListener() { |
||||
|
@Override |
||||
|
public void onRefresh() { |
||||
|
new RecentTask().execute(); |
||||
|
|
||||
|
} |
||||
|
|
||||
|
} |
||||
|
); |
||||
|
|
||||
|
|
||||
|
} |
||||
|
|
||||
|
return rootView; |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public void onAttach(Context context) { |
||||
|
super.onAttach(context); |
||||
|
if (context instanceof OnListFragmentInteractionListener) { |
||||
|
mListener = (OnListFragmentInteractionListener) context; |
||||
|
|
||||
|
} else { |
||||
|
throw new RuntimeException(context.toString() |
||||
|
+ " must implement OnFragmentInteractionListener"); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public void onDetach() { |
||||
|
super.onDetach(); |
||||
|
mListener = null; |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* This interface must be implemented by activities that contain this |
||||
|
* fragment to allow an interaction in this fragment to be communicated |
||||
|
* to the activity and potentially other fragments contained in that |
||||
|
* activity. |
||||
|
*/ |
||||
|
public interface OnListFragmentInteractionListener { |
||||
|
// TODO: Update argument type and name
|
||||
|
void onFragmentInteraction(TopicSummary topicSummary); |
||||
|
} |
||||
|
|
||||
|
|
||||
|
int n=0; |
||||
|
long s=0; |
||||
|
|
||||
|
|
||||
|
//---------------------------------------ASYNC TASK-----------------------------------
|
||||
|
|
||||
|
public class RecentTask extends AsyncTask<Void, Void, Integer> |
||||
|
{ |
||||
|
private static final String TAG="RecentTask"; |
||||
|
private final String thmmyUrl = "https://www.thmmy.gr/smf/index.php"; |
||||
|
|
||||
|
private Document document; |
||||
|
|
||||
|
|
||||
|
protected void onPreExecute() { |
||||
|
|
||||
|
progressBar.setVisibility(ProgressBar.VISIBLE); |
||||
|
} |
||||
|
|
||||
|
protected Integer doInBackground(Void... voids) |
||||
|
{ |
||||
|
|
||||
|
Request request = new Request.Builder() |
||||
|
.url(thmmyUrl) |
||||
|
.build(); |
||||
|
try { |
||||
|
Response response = client.newCall(request).execute(); |
||||
|
document = Jsoup.parse(response.body().string()); |
||||
|
parse(document); |
||||
|
return 0; |
||||
|
} catch (IOException e) { |
||||
|
Log.d("DEB", "ERROR", e); |
||||
|
return 1; |
||||
|
} catch (Exception e) { |
||||
|
Log.d("DEB", "ERROR", e); |
||||
|
return 2; |
||||
|
} |
||||
|
|
||||
|
} |
||||
|
|
||||
|
|
||||
|
|
||||
|
protected void onPostExecute(Integer result) |
||||
|
{ |
||||
|
|
||||
|
if(result==0) |
||||
|
recentAdapter.notifyDataSetChanged(); |
||||
|
else if (result==1) |
||||
|
Toast.makeText(getActivity(), "Network error", Toast.LENGTH_SHORT).show(); |
||||
|
|
||||
|
progressBar.setVisibility(ProgressBar.INVISIBLE); |
||||
|
swipeRefreshLayout.setRefreshing(false); |
||||
|
} |
||||
|
|
||||
|
private boolean 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("by (.*)"); |
||||
|
Matcher matcher = pattern.matcher(lastUser); |
||||
|
if (matcher.find()) |
||||
|
lastUser = matcher.group(1); |
||||
|
else |
||||
|
{ |
||||
|
Log.e(TAG, "Parsing failed (lastUser)!"); |
||||
|
return false; |
||||
|
} |
||||
|
|
||||
|
String dateTime = recent.get(i + 2).text(); |
||||
|
pattern = Pattern.compile("\\[(.*)\\]"); |
||||
|
matcher = pattern.matcher(dateTime); |
||||
|
if (matcher.find()) |
||||
|
dateTime = matcher.group(1); |
||||
|
else |
||||
|
{ |
||||
|
Log.e(TAG, "Parsing failed (dateTime)!"); |
||||
|
return false; |
||||
|
} |
||||
|
|
||||
|
|
||||
|
topicSummaries.add(new TopicSummary(link, title, lastUser, dateTime)); |
||||
|
} |
||||
|
|
||||
|
return true; |
||||
|
} |
||||
|
Log.e(TAG, "Parsing failed!"); |
||||
|
return false; |
||||
|
} |
||||
|
|
||||
|
// TODO: replace parse function with this when a method to get recent TOPICS and not POSTS becomes available
|
||||
|
// private boolean parse(String document) throws XmlPullParserException, IOException {
|
||||
|
// String text = null, tagName, link = null, title = null, poster = null,dateTime = null;
|
||||
|
// boolean posterFlag = false;
|
||||
|
// XmlPullParserFactory factory = XmlPullParserFactory.newInstance();
|
||||
|
// factory.setNamespaceAware(true);
|
||||
|
// XmlPullParser xpp = factory.newPullParser();
|
||||
|
//
|
||||
|
// xpp.setInput( new StringReader(document) );
|
||||
|
// int eventType = xpp.getEventType();
|
||||
|
// topicSummaries.clear();
|
||||
|
//
|
||||
|
// while (eventType != XmlPullParser.END_DOCUMENT) {
|
||||
|
// tagName = xpp.getName();
|
||||
|
// switch (eventType) {
|
||||
|
// case XmlPullParser.START_TAG:
|
||||
|
// if (tagName.equals("poster"))
|
||||
|
// posterFlag=true;
|
||||
|
// break;
|
||||
|
//
|
||||
|
// case XmlPullParser.TEXT:
|
||||
|
// text = xpp.getText();
|
||||
|
// break;
|
||||
|
//
|
||||
|
// case XmlPullParser.END_TAG:
|
||||
|
// switch (tagName)
|
||||
|
// {
|
||||
|
// case "recent-post":
|
||||
|
// topicSummaries.add(new TopicSummary(link, title, poster, dateTime));
|
||||
|
// break;
|
||||
|
// case "name":
|
||||
|
// if(posterFlag) {
|
||||
|
// poster = text;
|
||||
|
// posterFlag = false;
|
||||
|
// }
|
||||
|
// break;
|
||||
|
// case "link":
|
||||
|
// link = text;
|
||||
|
// break;
|
||||
|
// case "time":
|
||||
|
// dateTime = text;
|
||||
|
// break;
|
||||
|
// case "subject":
|
||||
|
// title = text;
|
||||
|
// break;
|
||||
|
// }
|
||||
|
// break;
|
||||
|
//
|
||||
|
// default:
|
||||
|
// break;
|
||||
|
// }
|
||||
|
// eventType = xpp.next();
|
||||
|
// }
|
||||
|
// return true;
|
||||
|
// }
|
||||
|
} |
||||
|
|
||||
|
} |
@ -0,0 +1,56 @@ |
|||||
|
package gr.thmmy.mthmmy.utils; |
||||
|
|
||||
|
import android.content.Context; |
||||
|
import android.support.annotation.Nullable; |
||||
|
import android.support.v7.widget.LinearLayoutManager; |
||||
|
import android.support.v7.widget.RecyclerView; |
||||
|
import android.util.AttributeSet; |
||||
|
|
||||
|
//Custom RecyclerView, so EdgeEffect and SwipeRefresh both work
|
||||
|
public class CustomRecyclerView extends RecyclerView { |
||||
|
private volatile boolean enableRefreshing=true; |
||||
|
|
||||
|
public CustomRecyclerView(Context context) { |
||||
|
super(context); |
||||
|
} |
||||
|
|
||||
|
public CustomRecyclerView(Context context, @Nullable AttributeSet attrs) { |
||||
|
super(context, attrs); |
||||
|
} |
||||
|
|
||||
|
public CustomRecyclerView(Context context, @Nullable AttributeSet attrs, int defStyle) { |
||||
|
super(context, attrs, defStyle); |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public void onScrolled(int dx, int dy) { |
||||
|
if(dy>0) |
||||
|
enableRefreshing=false; |
||||
|
super.onScrolled(dx, dy); |
||||
|
} |
||||
|
|
||||
|
|
||||
|
@Override |
||||
|
public void onScrollStateChanged(int state) |
||||
|
{ |
||||
|
if((state!=SCROLL_STATE_DRAGGING)&&((LinearLayoutManager)getLayoutManager()).findFirstCompletelyVisibleItemPosition()==0) |
||||
|
enableRefreshing=true; |
||||
|
else if(getChildCount()==0) |
||||
|
enableRefreshing=true; |
||||
|
else if(((LinearLayoutManager)getLayoutManager()).findFirstCompletelyVisibleItemPosition()!=0) |
||||
|
enableRefreshing=false; |
||||
|
|
||||
|
|
||||
|
|
||||
|
super.onScrollStateChanged(state); |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public boolean dispatchNestedScroll(int dxConsumed, int dyConsumed, int dxUnconsumed, int dyUnconsumed, int[] offsetInWindow) { |
||||
|
if(enableRefreshing) |
||||
|
return super.dispatchNestedScroll(dxConsumed, dyConsumed, dxUnconsumed, dyUnconsumed, offsetInWindow); |
||||
|
else |
||||
|
return super.dispatchNestedScroll(dxConsumed, dyConsumed, dxUnconsumed, 0, offsetInWindow); |
||||
|
} |
||||
|
|
||||
|
} |
@ -0,0 +1,309 @@ |
|||||
|
package gr.thmmy.mthmmy.utils; |
||||
|
|
||||
|
import android.os.Parcel; |
||||
|
import android.os.Parcelable; |
||||
|
import android.util.Log; |
||||
|
|
||||
|
import com.franmontiel.persistentcookiejar.PersistentCookieJar; |
||||
|
|
||||
|
import org.jsoup.Jsoup; |
||||
|
import org.jsoup.nodes.Document; |
||||
|
import org.jsoup.nodes.Element; |
||||
|
import org.jsoup.select.Elements; |
||||
|
|
||||
|
import java.util.List; |
||||
|
import java.util.regex.Matcher; |
||||
|
import java.util.regex.Pattern; |
||||
|
|
||||
|
import javax.net.ssl.SSLHandshakeException; |
||||
|
|
||||
|
import gr.thmmy.mthmmy.activities.BaseActivity; |
||||
|
import okhttp3.Cookie; |
||||
|
import okhttp3.FormBody; |
||||
|
import okhttp3.HttpUrl; |
||||
|
import okhttp3.OkHttpClient; |
||||
|
import okhttp3.Request; |
||||
|
import okhttp3.RequestBody; |
||||
|
import okhttp3.Response; |
||||
|
|
||||
|
|
||||
|
public class Thmmy |
||||
|
{ |
||||
|
private static final HttpUrl loginUrl = HttpUrl.parse("https://www.thmmy.gr/smf/index.php?action=login2"); |
||||
|
private static final HttpUrl indexUrl = HttpUrl.parse("https://www.thmmy.gr/smf/index.php"); |
||||
|
|
||||
|
public static final int OK = 1; |
||||
|
public static final int WRONG_USER= 2; |
||||
|
public static final int WRONG_PASSWORD= 3; |
||||
|
public static final int FAILED= 4; |
||||
|
public static final int CERTIFICATE_ERROR = 5; |
||||
|
public static final int OTHER_ERROR = 6; |
||||
|
|
||||
|
|
||||
|
|
||||
|
|
||||
|
|
||||
|
public static int authenticate(String username, String password) |
||||
|
{ |
||||
|
LoginData loginData = login(username, password, "60"); |
||||
|
|
||||
|
int status = loginData.getStatus(); |
||||
|
if (status==OK) |
||||
|
{ |
||||
|
logout(loginData.getLogoutLink()); |
||||
|
return OK; |
||||
|
} |
||||
|
return status; |
||||
|
|
||||
|
} |
||||
|
|
||||
|
|
||||
|
//-------------------------------------------LOGIN--------------------------------------------------
|
||||
|
//Two options: (username, password, duration) or nothing - cookies
|
||||
|
public static LoginData login(String... strings) |
||||
|
{ |
||||
|
Log.d("Login","Logging in..."); |
||||
|
LoginData loginData = new LoginData(); |
||||
|
Request request; |
||||
|
|
||||
|
if(strings.length==3) |
||||
|
{ |
||||
|
String loginName = strings[0]; |
||||
|
String password = strings[1]; |
||||
|
String duration = strings[2]; |
||||
|
|
||||
|
((PersistentCookieJar) BaseActivity.getCookieJar()).clear(); |
||||
|
|
||||
|
RequestBody formBody = new FormBody.Builder() |
||||
|
.add("user", loginName) |
||||
|
.add("passwrd", password) |
||||
|
.add("cookielength", duration) //Forever is -1
|
||||
|
.build(); |
||||
|
request = new Request.Builder() |
||||
|
.url(loginUrl) |
||||
|
.post(formBody) |
||||
|
.build(); |
||||
|
} |
||||
|
else |
||||
|
{ |
||||
|
request = new Request.Builder() |
||||
|
.url(loginUrl) |
||||
|
.build(); |
||||
|
} |
||||
|
|
||||
|
OkHttpClient client = new OkHttpClient.Builder() |
||||
|
.cookieJar(BaseActivity.getCookieJar()) |
||||
|
.build(); |
||||
|
|
||||
|
|
||||
|
try |
||||
|
{ |
||||
|
Response response = client.newCall(request).execute(); |
||||
|
Document document = Jsoup.parse(response.body().string()); |
||||
|
|
||||
|
Element logout = document.getElementById("logoutbtn"); |
||||
|
|
||||
|
if (logout != null) |
||||
|
{ |
||||
|
Log.i("Login", "Login successful"); |
||||
|
setPersistentCookieSession(); |
||||
|
loginData.setUsername(extractUserName(document)); |
||||
|
loginData.setLogoutLink(HttpUrl.parse(logout.attr("href"))); |
||||
|
loginData.setStatus(OK); |
||||
|
} |
||||
|
else |
||||
|
{ |
||||
|
Log.w("Login", "Login failed"); |
||||
|
loginData.setStatus(FAILED); |
||||
|
|
||||
|
//Making error more specific
|
||||
|
Elements error = document.select("b:contains(That username does not exist.)"); |
||||
|
|
||||
|
if (error.size()==1) |
||||
|
{ |
||||
|
loginData.setStatus(WRONG_USER); |
||||
|
Log.d("Login","Wrong Username"); |
||||
|
} |
||||
|
|
||||
|
error = document.select("body:contains(Password incorrect)"); |
||||
|
if (error.size()==1) |
||||
|
{ |
||||
|
Log.d("Login","Wrong Password"); |
||||
|
loginData.setStatus(WRONG_PASSWORD); |
||||
|
} |
||||
|
|
||||
|
((PersistentCookieJar) BaseActivity.getCookieJar()).clear(); |
||||
|
|
||||
|
} |
||||
|
} catch (SSLHandshakeException e) { |
||||
|
Log.w("Login", "Certificate problem"); |
||||
|
loginData.setStatus(CERTIFICATE_ERROR); |
||||
|
|
||||
|
} catch (Exception e) { |
||||
|
Log.e("Login", "Error", e); |
||||
|
loginData.setStatus(OTHER_ERROR); |
||||
|
} |
||||
|
|
||||
|
|
||||
|
|
||||
|
return loginData; |
||||
|
|
||||
|
|
||||
|
} |
||||
|
|
||||
|
public static class LoginData implements Parcelable |
||||
|
{ |
||||
|
private int status; |
||||
|
private String username; |
||||
|
private HttpUrl logoutLink; |
||||
|
|
||||
|
public LoginData() {} |
||||
|
|
||||
|
public String getUsername() { |
||||
|
return username; |
||||
|
} |
||||
|
|
||||
|
public void setUsername(String username) { |
||||
|
this.username = username; |
||||
|
} |
||||
|
|
||||
|
|
||||
|
public int getStatus() { |
||||
|
return status; |
||||
|
} |
||||
|
|
||||
|
public void setStatus(int status) { |
||||
|
this.status = status; |
||||
|
} |
||||
|
|
||||
|
|
||||
|
public HttpUrl getLogoutLink() { |
||||
|
return logoutLink; |
||||
|
} |
||||
|
|
||||
|
public void setLogoutLink(HttpUrl logoutLink) { |
||||
|
this.logoutLink = logoutLink; |
||||
|
} |
||||
|
|
||||
|
|
||||
|
public int describeContents() { |
||||
|
return 0; |
||||
|
} |
||||
|
|
||||
|
public void writeToParcel(Parcel out, int flags) { |
||||
|
out.writeInt(status); |
||||
|
out.writeString(username); |
||||
|
out.writeString(logoutLink.toString()); |
||||
|
} |
||||
|
|
||||
|
public static final Parcelable.Creator<LoginData> CREATOR |
||||
|
= new Parcelable.Creator<LoginData>() { |
||||
|
public LoginData createFromParcel(Parcel in) { |
||||
|
return new LoginData(in); |
||||
|
} |
||||
|
|
||||
|
public LoginData[] newArray(int size) { |
||||
|
return new LoginData[size]; |
||||
|
} |
||||
|
}; |
||||
|
|
||||
|
private LoginData(Parcel in) { |
||||
|
status = in.readInt(); |
||||
|
username=in.readString(); |
||||
|
logoutLink=HttpUrl.parse(in.readString()); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
private static boolean setPersistentCookieSession() |
||||
|
{ |
||||
|
List<Cookie> cookieList = BaseActivity.getCookieJar().loadForRequest(HttpUrl.parse("https://www.thmmy.gr")); |
||||
|
|
||||
|
if (cookieList.size() == 2) { |
||||
|
if ((cookieList.get(0).name().equals("THMMYgrC00ki3")) && (cookieList.get(1).name().equals("PHPSESSID"))) |
||||
|
{ |
||||
|
Cookie.Builder builder = new Cookie.Builder(); |
||||
|
builder.name(cookieList.get(1).name()) |
||||
|
.value(cookieList.get(1).value()) |
||||
|
.domain(cookieList.get(1).domain()) |
||||
|
.expiresAt(cookieList.get(0).expiresAt()); |
||||
|
cookieList.remove(1); |
||||
|
cookieList.add(builder.build()); |
||||
|
BaseActivity.getSharedPrefsCookiePersistor().clear(); |
||||
|
BaseActivity.getSharedPrefsCookiePersistor().saveAll(cookieList); |
||||
|
return true; |
||||
|
} |
||||
|
} |
||||
|
return false; |
||||
|
} |
||||
|
//-------------------------------------LOGIN ENDS-----------------------------------------------
|
||||
|
|
||||
|
|
||||
|
|
||||
|
//--------------------------------------LOGOUT--------------------------------------------------
|
||||
|
//Two options: (username, password, duration) or nothing - cookies
|
||||
|
public static int logout(HttpUrl logoutLink) |
||||
|
{ |
||||
|
OkHttpClient client = new OkHttpClient.Builder() |
||||
|
.cookieJar(BaseActivity.getCookieJar()) //cookies will be deleted
|
||||
|
.build(); |
||||
|
Request request = new Request.Builder() |
||||
|
.url(logoutLink) |
||||
|
.build(); |
||||
|
|
||||
|
try { |
||||
|
Response response = client.newCall(request).execute(); |
||||
|
Document document = Jsoup.parse(response.body().string()); |
||||
|
|
||||
|
Elements login = document.select("[value=Login]"); |
||||
|
if(!login.isEmpty()) |
||||
|
{ |
||||
|
Log.i("Logout", "Logout successful"); |
||||
|
return OK; |
||||
|
} |
||||
|
else |
||||
|
{ |
||||
|
Log.w("Logout", "Logout failed"); |
||||
|
return FAILED; |
||||
|
} |
||||
|
} catch (SSLHandshakeException e) { |
||||
|
Log.w("Logout", "Certificate problem (please switch to unsafe connection)."); |
||||
|
return CERTIFICATE_ERROR; |
||||
|
|
||||
|
} catch (Exception e) { |
||||
|
Log.d("Logout", "ERROR", e); |
||||
|
return OTHER_ERROR; |
||||
|
} |
||||
|
|
||||
|
|
||||
|
} |
||||
|
|
||||
|
|
||||
|
|
||||
|
|
||||
|
//----------------------------------------LOGOUT ENDS-----------------------------------------------
|
||||
|
|
||||
|
|
||||
|
|
||||
|
|
||||
|
//-------------------------------------------MISC---------------------------------------------------
|
||||
|
public static String extractUserName(Document doc) |
||||
|
{ |
||||
|
if(doc!=null) |
||||
|
{ |
||||
|
Elements user = doc.select("div[id=myuser] > h3"); |
||||
|
|
||||
|
if (user.size()==1) |
||||
|
{ |
||||
|
String txt = user.first().ownText(); |
||||
|
|
||||
|
Pattern pattern = Pattern.compile(", (.*?),"); |
||||
|
Matcher matcher = pattern.matcher(txt); |
||||
|
if (matcher.find()) |
||||
|
return matcher.group(1); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
return null; |
||||
|
} |
||||
|
|
||||
|
} |
@ -0,0 +1,6 @@ |
|||||
|
<?xml version="1.0" encoding="utf-8"?> |
||||
|
<shape xmlns:android="http://schemas.android.com/apk/res/android" |
||||
|
android:shape="rectangle"> |
||||
|
<solid android:color="@color/white" /> |
||||
|
<corners android:radius="2dp" /> |
||||
|
</shape> |
@ -0,0 +1,48 @@ |
|||||
|
<?xml version="1.0" encoding="utf-8"?> |
||||
|
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android" |
||||
|
android:id="@+id/scrollview" |
||||
|
android:layout_width="match_parent" |
||||
|
android:layout_height="match_parent"> |
||||
|
|
||||
|
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" |
||||
|
xmlns:tools="http://schemas.android.com/tools" |
||||
|
android:layout_width="match_parent" |
||||
|
android:layout_height="wrap_content" |
||||
|
android:paddingLeft="@dimen/activity_horizontal_margin" |
||||
|
android:paddingRight="@dimen/activity_horizontal_margin" |
||||
|
android:paddingTop="@dimen/activity_vertical_margin" |
||||
|
android:paddingBottom="@dimen/activity_vertical_margin" |
||||
|
tools:context="com.eternalpixels.toinfinity.Info"> |
||||
|
|
||||
|
<TextView android:id="@+id/appName" |
||||
|
android:text="@string/app_name" |
||||
|
android:layout_width="wrap_content" |
||||
|
android:layout_height="wrap_content" |
||||
|
android:textAppearance="?android:attr/textAppearanceLarge" |
||||
|
android:layout_alignParentTop="true" |
||||
|
android:layout_centerHorizontal="true" |
||||
|
android:textStyle="bold" /> |
||||
|
|
||||
|
<TextView |
||||
|
android:layout_width="wrap_content" |
||||
|
android:layout_height="wrap_content" |
||||
|
android:textAppearance="?android:attr/textAppearanceSmall" |
||||
|
android:id="@+id/version" |
||||
|
android:layout_below="@+id/appName" |
||||
|
android:layout_centerHorizontal="true" |
||||
|
android:textStyle="italic" /> |
||||
|
|
||||
|
|
||||
|
<ImageView |
||||
|
android:contentDescription="@string/logo" |
||||
|
android:layout_margin="15dp" |
||||
|
android:layout_width="wrap_content" |
||||
|
android:layout_height="wrap_content" |
||||
|
android:id="@+id/logoView" |
||||
|
android:src="@mipmap/ic_launcher" |
||||
|
android:layout_below="@id/version" |
||||
|
android:layout_centerHorizontal="true" /> |
||||
|
|
||||
|
|
||||
|
</RelativeLayout> |
||||
|
</ScrollView> |
@ -0,0 +1,42 @@ |
|||||
|
<?xml version="1.0" encoding="utf-8"?> |
||||
|
<android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android" |
||||
|
xmlns:app="http://schemas.android.com/apk/res-auto" |
||||
|
xmlns:tools="http://schemas.android.com/tools" |
||||
|
android:id="@+id/main_content" |
||||
|
android:layout_width="match_parent" |
||||
|
android:layout_height="match_parent" |
||||
|
android:fitsSystemWindows="true" |
||||
|
tools:context=".activities.MainActivity"> |
||||
|
|
||||
|
<android.support.design.widget.AppBarLayout |
||||
|
android:id="@+id/appbar" |
||||
|
android:layout_width="match_parent" |
||||
|
android:layout_height="wrap_content" |
||||
|
android:paddingTop="@dimen/appbar_padding_top" |
||||
|
android:theme="@style/ToolbarTheme"> |
||||
|
|
||||
|
<android.support.v7.widget.Toolbar |
||||
|
android:id="@+id/toolbar" |
||||
|
android:layout_width="match_parent" |
||||
|
android:layout_height="?attr/actionBarSize" |
||||
|
android:background="?attr/colorPrimary" |
||||
|
app:popupTheme="@style/popupTheme"> |
||||
|
|
||||
|
</android.support.v7.widget.Toolbar> |
||||
|
|
||||
|
<android.support.design.widget.TabLayout |
||||
|
android:id="@+id/tabs" |
||||
|
android:layout_width="match_parent" |
||||
|
android:layout_height="wrap_content" /> |
||||
|
|
||||
|
</android.support.design.widget.AppBarLayout> |
||||
|
|
||||
|
<android.support.v4.view.ViewPager |
||||
|
android:id="@+id/container" |
||||
|
android:layout_width="match_parent" |
||||
|
android:layout_height="match_parent" |
||||
|
app:layout_behavior="@string/appbar_scrolling_view_behavior" /> |
||||
|
|
||||
|
|
||||
|
|
||||
|
</android.support.design.widget.CoordinatorLayout> |
@ -0,0 +1,35 @@ |
|||||
|
<?xml version="1.0" encoding="utf-8"?> |
||||
|
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" |
||||
|
xmlns:tools="http://schemas.android.com/tools" |
||||
|
xmlns:app="http://schemas.android.com/apk/res-auto" |
||||
|
android:layout_width="match_parent" |
||||
|
android:layout_height="match_parent" |
||||
|
android:paddingBottom="@dimen/activity_vertical_margin" |
||||
|
android:paddingLeft="@dimen/activity_horizontal_margin" |
||||
|
android:paddingRight="@dimen/activity_horizontal_margin" |
||||
|
android:paddingTop="@dimen/activity_vertical_margin" |
||||
|
tools:context="gr.thmmy.mthmmy.activities.TopicActivity"> |
||||
|
|
||||
|
<view |
||||
|
class="gr.thmmy.mthmmy.utils.CustomRecyclerView" |
||||
|
android:id="@+id/list" |
||||
|
android:name="gr.thmmy.mthmmy.activities.Topic" |
||||
|
android:layout_width="match_parent" |
||||
|
android:layout_height="match_parent" |
||||
|
android:paddingTop="4dp" |
||||
|
android:paddingBottom="4dp" |
||||
|
android:clipToPadding="false" |
||||
|
android:background="@color/background" |
||||
|
app:layoutManager="LinearLayoutManager" |
||||
|
tools:context="gr.thmmy.mthmmy.activities.TopicActivity" |
||||
|
tools:listitem="@layout/fragment_recent_row" /> |
||||
|
|
||||
|
<ProgressBar |
||||
|
android:visibility="invisible" |
||||
|
android:layout_width="wrap_content" |
||||
|
android:layout_height="wrap_content" |
||||
|
android:id="@+id/progressBar" |
||||
|
android:layout_centerVertical="true" |
||||
|
android:layout_centerHorizontal="true" /> |
||||
|
|
||||
|
</RelativeLayout> |
@ -0,0 +1,32 @@ |
|||||
|
<?xml version="1.0" encoding="utf-8"?> |
||||
|
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" |
||||
|
android:layout_width="match_parent" |
||||
|
android:layout_height="match_parent" |
||||
|
android:layout_marginBottom="5dp"> |
||||
|
|
||||
|
<TextView |
||||
|
android:layout_width="match_parent" |
||||
|
android:layout_height="wrap_content" |
||||
|
android:layout_alignParentTop="true" |
||||
|
android:layout_alignParentLeft="true" |
||||
|
android:layout_alignParentStart="true" |
||||
|
android:text="Author" |
||||
|
android:id="@+id/author" /> |
||||
|
|
||||
|
<TextView |
||||
|
android:layout_width="wrap_content" |
||||
|
android:layout_height="wrap_content" |
||||
|
android:layout_alignBaseline="@+id/author" |
||||
|
android:layout_alignParentRight="true" |
||||
|
android:layout_alignParentEnd="true" |
||||
|
android:text="DateTime" |
||||
|
android:id="@+id/dateTime" /> |
||||
|
|
||||
|
<WebView |
||||
|
android:layout_width="match_parent" |
||||
|
android:layout_height="match_parent" |
||||
|
android:id="@+id/content" |
||||
|
android:layout_below="@+id/author" |
||||
|
android:layout_alignRight="@+id/dateTime" |
||||
|
android:layout_alignEnd="@+id/dateTime" /> |
||||
|
</RelativeLayout> |
@ -0,0 +1,38 @@ |
|||||
|
<?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" |
||||
|
xmlns:tools="http://schemas.android.com/tools" |
||||
|
android:layout_height="match_parent" |
||||
|
android:layout_width="match_parent"> |
||||
|
|
||||
|
<android.support.v4.widget.SwipeRefreshLayout |
||||
|
android:id="@+id/swiperefresh" |
||||
|
android:layout_width="match_parent" |
||||
|
android:layout_height="match_parent"> |
||||
|
|
||||
|
<view |
||||
|
class="gr.thmmy.mthmmy.utils.CustomRecyclerView" |
||||
|
android:id="@+id/list" |
||||
|
android:name="gr.thmmy.mthmmy.sections.recent.RecentFragment" |
||||
|
android:layout_width="match_parent" |
||||
|
android:layout_height="match_parent" |
||||
|
android:paddingTop="4dp" |
||||
|
android:paddingBottom="4dp" |
||||
|
android:clipToPadding="false" |
||||
|
android:background="@color/background" |
||||
|
app:layoutManager="LinearLayoutManager" |
||||
|
tools:context="gr.thmmy.mthmmy.sections.recent.RecentFragment" |
||||
|
tools:listitem="@layout/fragment_recent_row" /> |
||||
|
|
||||
|
</android.support.v4.widget.SwipeRefreshLayout> |
||||
|
|
||||
|
<ProgressBar |
||||
|
android:visibility="invisible" |
||||
|
android:layout_width="wrap_content" |
||||
|
android:layout_height="wrap_content" |
||||
|
android:id="@+id/progressBar" |
||||
|
android:layout_centerVertical="true" |
||||
|
android:layout_centerHorizontal="true" /> |
||||
|
|
||||
|
</RelativeLayout> |
@ -0,0 +1,66 @@ |
|||||
|
<?xml version="1.0" encoding="utf-8"?> |
||||
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" |
||||
|
xmlns:app="http://schemas.android.com/apk/res-auto" |
||||
|
android:layout_width="wrap_content" |
||||
|
android:layout_height="wrap_content" |
||||
|
android:paddingEnd="4dp" |
||||
|
android:paddingStart="4dp" |
||||
|
android:orientation="vertical"> |
||||
|
|
||||
|
<android.support.v7.widget.CardView |
||||
|
xmlns:card_view="http://schemas.android.com/apk/res-auto" |
||||
|
android:id="@+id/card_view" |
||||
|
android:layout_gravity="center" |
||||
|
android:layout_width="match_parent" |
||||
|
android:layout_height="wrap_content" |
||||
|
android:foreground="?android:attr/selectableItemBackground" |
||||
|
card_view:cardPreventCornerOverlap="false" |
||||
|
card_view:cardUseCompatPadding="true" |
||||
|
card_view:cardCornerRadius="4dp" |
||||
|
card_view:cardBackgroundColor="@color/colorPrimary"> |
||||
|
|
||||
|
<RelativeLayout |
||||
|
android:layout_width="wrap_content" |
||||
|
android:layout_height="wrap_content" |
||||
|
android:paddingTop="6dp" |
||||
|
android:paddingBottom="6dp" |
||||
|
android:paddingLeft="10dp" |
||||
|
android:paddingRight="10dp" |
||||
|
android:layout_alignParentTop="true"> |
||||
|
|
||||
|
<TextView |
||||
|
android:id="@+id/title" |
||||
|
android:layout_width="match_parent" |
||||
|
android:layout_height="wrap_content" |
||||
|
android:layout_alignParentTop="true" |
||||
|
android:layout_alignParentLeft="true" |
||||
|
android:layout_alignParentStart="true" |
||||
|
android:textAppearance="?attr/textAppearanceListItem" |
||||
|
android:textColor="@color/myColor1" /> |
||||
|
|
||||
|
<TextView |
||||
|
android:id="@+id/dateTime" |
||||
|
android:layout_width="wrap_content" |
||||
|
android:layout_height="wrap_content" |
||||
|
android:layout_below="@+id/title" |
||||
|
android:layout_alignParentLeft="true" |
||||
|
android:layout_alignParentStart="true" |
||||
|
android:textColor="@color/myColor2"/> |
||||
|
|
||||
|
<TextView |
||||
|
android:id="@+id/lastUser" |
||||
|
android:textStyle="italic" |
||||
|
android:layout_width="wrap_content" |
||||
|
android:layout_height="wrap_content" |
||||
|
android:layout_alignBaseline="@+id/dateTime" |
||||
|
android:layout_alignBottom="@+id/dateTime" |
||||
|
android:layout_alignParentRight="true" |
||||
|
android:layout_alignParentEnd="true" |
||||
|
android:textColor="@color/myColor2"/> |
||||
|
|
||||
|
</RelativeLayout> |
||||
|
|
||||
|
</android.support.v7.widget.CardView> |
||||
|
|
||||
|
|
||||
|
</LinearLayout> |
@ -0,0 +1,15 @@ |
|||||
|
<menu xmlns:android="http://schemas.android.com/apk/res/android" |
||||
|
xmlns:app="http://schemas.android.com/apk/res-auto" |
||||
|
xmlns:tools="http://schemas.android.com/tools" |
||||
|
tools:context=".activities.MainActivity"> |
||||
|
<item |
||||
|
android:id="@+id/action_login" |
||||
|
android:orderInCategory="100" |
||||
|
android:title="@string/login" |
||||
|
app:showAsAction="never" /> |
||||
|
<item |
||||
|
android:id="@+id/action_about" |
||||
|
android:orderInCategory="200" |
||||
|
android:title="@string/about" |
||||
|
app:showAsAction="never" /> |
||||
|
</menu> |
@ -0,0 +1,9 @@ |
|||||
|
<resources> |
||||
|
|
||||
|
<style name="AppTheme.NoActionBar"> |
||||
|
<item name="windowActionBar">false</item> |
||||
|
<item name="windowNoTitle">true</item> |
||||
|
<item name="android:windowDrawsSystemBarBackgrounds">true</item> |
||||
|
<item name="android:statusBarColor">@android:color/transparent</item> |
||||
|
</style> |
||||
|
</resources> |
@ -0,0 +1,6 @@ |
|||||
|
<resources> |
||||
|
<!-- Example customization of dimensions originally defined in res/values/dimens.xml |
||||
|
(such as screen margins) for screens with more than 820dp of available width. This |
||||
|
would include 7" and 10" devices in landscape (~960dp and ~1280dp respectively). --> |
||||
|
<dimen name="activity_horizontal_margin">64dp</dimen> |
||||
|
</resources> |
@ -1,6 +1,19 @@ |
|||||
<?xml version="1.0" encoding="utf-8"?> |
<?xml version="1.0" encoding="utf-8"?> |
||||
<resources> |
<resources> |
||||
<color name="colorPrimary">#3F51B5</color> |
<color name="colorPrimary">#313335</color> |
||||
<color name="colorPrimaryDark">#303F9F</color> |
<color name="colorPrimaryDark">#2b2b2b</color> |
||||
<color name="colorAccent">#FF4081</color> |
<color name="colorPrimaryLight">#616161</color> |
||||
|
<color name="colorAccent">#2b2b2b</color> |
||||
|
|
||||
|
<color name="transparent">#00000000</color> |
||||
|
|
||||
|
<color name="white">#ffffff</color> |
||||
|
<color name="background">#616161</color> |
||||
|
|
||||
|
<color name="myColor1">#ffb74d</color> |
||||
|
<color name="myColor2">#1e88e5</color> |
||||
|
<color name="myColor3">#f57f17</color> |
||||
|
<color name="myColor4">#7e57c2</color> |
||||
|
<color name="myColor5">#388e3c</color> |
||||
|
<color name="myColor6">#d32f2f</color> |
||||
</resources> |
</resources> |
||||
|
@ -0,0 +1,7 @@ |
|||||
|
<resources> |
||||
|
<!-- Default screen margins, per the Android Design guidelines. --> |
||||
|
<dimen name="activity_horizontal_margin">16dp</dimen> |
||||
|
<dimen name="activity_vertical_margin">16dp</dimen> |
||||
|
<dimen name="fab_margin">16dp</dimen> |
||||
|
<dimen name="appbar_padding_top">8dp</dimen> |
||||
|
</resources> |
@ -1,3 +1,11 @@ |
|||||
<resources> |
<resources> |
||||
<string name="app_name">mTHMMY</string> |
<string name="app_name">mTHMMY</string> |
||||
|
<string name="action_settings">Settings</string> |
||||
|
<string name="section_format">Hello World from section: %1$d</string> |
||||
|
|
||||
|
<string name="about">About</string> |
||||
|
<string name="version">v%1$s</string> |
||||
|
<string name="logo">logo</string> |
||||
|
<string name="profile_name">Name</string> |
||||
|
<string name="login">Login</string> |
||||
</resources> |
</resources> |
||||
|
@ -1,17 +0,0 @@ |
|||||
package gr.thmmy.mthmmy; |
|
||||
|
|
||||
import org.junit.Test; |
|
||||
|
|
||||
import static org.junit.Assert.*; |
|
||||
|
|
||||
/** |
|
||||
* Example local unit test, which will execute on the development machine (host). |
|
||||
* |
|
||||
* @see <a href="http://d.android.com/tools/testing">Testing documentation</a> |
|
||||
*/ |
|
||||
public class ExampleUnitTest { |
|
||||
@Test |
|
||||
public void addition_isCorrect() throws Exception { |
|
||||
assertEquals(4, 2 + 2); |
|
||||
} |
|
||||
} |
|
Loading…
Reference in new issue