diff --git a/app/build.gradle b/app/build.gradle index 659247f2..2b37d81e 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -6,7 +6,7 @@ android { defaultConfig { applicationId "gr.thmmy.mthmmy" - minSdkVersion 16 + minSdkVersion 19 targetSdkVersion 25 versionCode 2 versionName "0.16" @@ -22,7 +22,7 @@ android { dependencies { compile fileTree(dir: 'libs', include: ['*.jar']) compile 'com.android.support:appcompat-v7:25.0.1' - compile 'com.android.support:design:25.0.1' + compile 'com.android.support:design:25.0.0' compile 'com.squareup.okhttp3:okhttp:3.4.0' compile 'com.jakewharton:butterknife:7.0.1' compile 'org.jsoup:jsoup:1.10.1' diff --git a/app/src/main/java/gr/thmmy/mthmmy/activities/AboutActivity.java b/app/src/main/java/gr/thmmy/mthmmy/activities/AboutActivity.java index bb457ced..1959f891 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/activities/AboutActivity.java +++ b/app/src/main/java/gr/thmmy/mthmmy/activities/AboutActivity.java @@ -13,8 +13,8 @@ public class AboutActivity extends BaseActivity { super.onCreate(savedInstanceState); setContentView(R.layout.activity_about); String versionName = BuildConfig.VERSION_NAME; - TextView tv= (TextView) findViewById(R.id.version); - if(tv!=null) + TextView tv = (TextView) findViewById(R.id.version); + if (tv != null) tv.setText(getString(R.string.version, versionName)); //TODO: add licenses diff --git a/app/src/main/java/gr/thmmy/mthmmy/activities/BaseActivity.java b/app/src/main/java/gr/thmmy/mthmmy/activities/BaseActivity.java index ccefaf6a..16054e5c 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/activities/BaseActivity.java +++ b/app/src/main/java/gr/thmmy/mthmmy/activities/BaseActivity.java @@ -1,61 +1,281 @@ package gr.thmmy.mthmmy.activities; +import android.content.SharedPreferences; import android.os.Bundle; import android.support.v7.app.AppCompatActivity; +import android.util.Log; import com.franmontiel.persistentcookiejar.PersistentCookieJar; import com.franmontiel.persistentcookiejar.cache.SetCookieCache; import com.franmontiel.persistentcookiejar.persistence.SharedPrefsCookiePersistor; -import gr.thmmy.mthmmy.utils.Thmmy; +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.List; +import java.util.Objects; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import javax.net.ssl.SSLHandshakeException; + +import okhttp3.Cookie; import okhttp3.CookieJar; +import okhttp3.FormBody; +import okhttp3.HttpUrl; import okhttp3.OkHttpClient; +import okhttp3.Request; +import okhttp3.RequestBody; +import okhttp3.Response; public class BaseActivity extends AppCompatActivity { - //Shared preferences - static final String SHARED_PREFS_NAME = "thmmySharedPrefs"; +//----------------------------------------CLASS VARIABLES----------------------------------------- + /* --Response Codes-- */ + static final int LOGGED_OUT = 0; + static final int LOGGED_IN = 1; + static final int WRONG_USER = 2; + static final int WRONG_PASSWORD = 3; + static final int FAILED = 4; + static final int CERTIFICATE_ERROR = 5; + static final int OTHER_ERROR = 6; + /* --Response Codes End-- */ + /* --Shared Preferences-- */ static final String USER_NAME = "userNameKey"; static final String GUEST_PREF_USERNAME = "GUEST"; - static final String IS_LOGGED_IN = "isLoggedIn"; + static final String LOG_STATUS = "isLoggedIn"; + private static final String SHARED_PREFS_NAME = "thmmySharedPrefs"; + static SharedPreferences _prefs; + /* --Shared Preferences End-- */ + + /* --Client Stuff-- */ static OkHttpClient client; - static Thmmy.LoginData loginData; private static CookieJar cookieJar; private static SharedPrefsCookiePersistor sharedPrefsCookiePersistor; - private static boolean init =false; //To initialize stuff only once per app start + /* --Client Stuff End-- */ + + //Other variables + private static boolean init = false; //To initialize stuff only once per app start + private static final String TAG = "BaseActivity"; +//--------------------------------------CLASS VARIABLES END--------------------------------------- - public static CookieJar getCookieJar() - { +//-------------------------------------CLIENT AND COOKIES----------------------------------------- + private static CookieJar getCookieJar() { return cookieJar; } - public static SharedPrefsCookiePersistor getSharedPrefsCookiePersistor() { + private static SharedPrefsCookiePersistor getSharedPrefsCookiePersistor() { return sharedPrefsCookiePersistor; } public static OkHttpClient getClient() { return client; } +//-----------------------------------CLIENT AND COOKIES END--------------------------------------- @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); - if(!init) - { + if (!init) { + _prefs = getSharedPreferences(SHARED_PREFS_NAME, MODE_PRIVATE); sharedPrefsCookiePersistor = new SharedPrefsCookiePersistor(BaseActivity.this); cookieJar = new PersistentCookieJar(new SetCookieCache(), sharedPrefsCookiePersistor); client = new OkHttpClient.Builder() .cookieJar(cookieJar) .build(); - loginData = new Thmmy.LoginData(); - loginData.setStatus(0); - init =true; + init = true; } } - void setLoginData(Thmmy.LoginData loginData) { - BaseActivity.loginData = loginData; + /* + THMMY CLASS + -- inner class of BaseActivity + + This class handles all session related operations (e.g. login, logout) + Also stores data to SharedPreferences file. + */ + +//---------------------------------------INNER CLASS BEGINS--------------------------------------- + public static class Thmmy { + //Class variables + 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"); + + +//-------------------------------------------LOGIN------------------------------------------------ + //Two options: (username, password, duration) or nothing - cookies + static void login(String... strings) { + Log.d("Login", "Logging in..."); + Request request; + + if (strings.length == 3) { //Actual login + String loginName = strings[0]; + String password = strings[1]; + String duration = strings[2]; + + ((PersistentCookieJar) getCookieJar()).clear(); + + RequestBody formBody = new FormBody.Builder() //Build login form + .add("user", loginName) + .add("passwrd", password) + .add("cookielength", duration) //Forever is -1 + .build(); + request = new Request.Builder() //Build the request + .url(loginUrl) + .post(formBody) + .build(); + } else { //Already logged in, just get cookies + request = new Request.Builder() //Build the request + .url(loginUrl) + .build(); + } + + try { + Response response = client.newCall(request).execute(); //Make the request + /* --Handle response-- */ + Document document = Jsoup.parse(response.body().string()); + Element logout = document.getElementById("logoutbtn"); //Get logout button + + if (logout != null) { //If there is a logout button, then I successfully logged in + Log.i("Login", "Login successful"); + setPersistentCookieSession(); + + //Edit SharedPreferences, save session's data + _prefs.edit().putString(USER_NAME, extractUserName(document)).apply(); + _prefs.edit().putInt(LOG_STATUS, LOGGED_IN).apply(); + } else { //I am not logged in, what went wrong? + Log.w("Login", "Login failed"); + _prefs.edit().putInt(LOG_STATUS, FAILED).apply(); //Request failed + + //Making error more specific + + Elements error = document.select("b:contains(That username does not exist.)"); + if (error.size() == 1) { //Wrong username + _prefs.edit().putInt(LOG_STATUS, WRONG_USER).apply(); + Log.d("Login", "Wrong Username"); + } + + error = document.select("body:contains(Password incorrect)"); + if (error.size() == 1) { //Wrong password + _prefs.edit().putInt(LOG_STATUS, WRONG_PASSWORD).apply(); + Log.d("Login", "Wrong Password"); + } + + ((PersistentCookieJar) getCookieJar()).clear(); + + } + //Request exception handling + } catch (SSLHandshakeException e) { + _prefs.edit().putInt(LOG_STATUS, CERTIFICATE_ERROR).apply(); + Log.w("Login", "Certificate problem"); + + } catch (Exception e) { + _prefs.edit().putInt(LOG_STATUS, OTHER_ERROR).apply(); + Log.e("Login", "Error", e); + } + } +//--------------------------------------LOGIN ENDS------------------------------------------------ + +//---------------------------------------LOGOUT--------------------------------------------------- + static int logout() { + String _logout_link = ""; + { //Find current logout link + try { + //Build and make a request for the index (home) page + Request request = new Request.Builder() + .url(indexUrl) + .build(); + Response response = client.newCall(request).execute(); + Document document = Jsoup.parse(response.body().string()); + Element logout = document.getElementById("logoutbtn"); //Find the logout button + _logout_link = HttpUrl.parse(logout.attr("href")).toString(); //Get the url + } catch (IOException e) { + e.printStackTrace(); + } + } + + if (Objects.equals(_logout_link, "")) { //If logout button wasn't found + return OTHER_ERROR; //Something went wrong + } + + //Attempt logout + OkHttpClient client = getClient(); + Request request = new Request.Builder() + .url(_logout_link) + .build(); + + try { + Response response = client.newCall(request).execute(); + Document document = Jsoup.parse(response.body().string()); + + Elements login = document.select("[value=Login]"); //Find login button + ((PersistentCookieJar) getCookieJar()).clear(); + if (!login.isEmpty()) { //If found, logout was successful + Log.i("Logout", "Logout successful"); + _prefs.edit().clear().apply(); //Clear session data + //User is now guest + _prefs.edit().putString(USER_NAME, GUEST_PREF_USERNAME).apply(); + _prefs.edit().putInt(LOG_STATUS, LOGGED_IN).apply(); + return LOGGED_OUT; + } 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------------------------------------------------- + private 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; + } + + private static void setPersistentCookieSession() { + List cookieList = 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()); + getSharedPrefsCookiePersistor().clear(); + getSharedPrefsCookiePersistor().saveAll(cookieList); + } + } + } } +//----------------------------------------INNER CLASS ENDS---------------------------------------- } diff --git a/app/src/main/java/gr/thmmy/mthmmy/activities/LoginActivity.java b/app/src/main/java/gr/thmmy/mthmmy/activities/LoginActivity.java index 9d4830d0..f741f0db 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/activities/LoginActivity.java +++ b/app/src/main/java/gr/thmmy/mthmmy/activities/LoginActivity.java @@ -2,7 +2,6 @@ package gr.thmmy.mthmmy.activities; import android.app.ProgressDialog; import android.content.Intent; -import android.content.SharedPreferences; import android.os.AsyncTask; import android.os.Bundle; import android.util.Log; @@ -13,61 +12,62 @@ import android.widget.Toast; import gr.thmmy.mthmmy.R; -import static gr.thmmy.mthmmy.utils.Thmmy.CERTIFICATE_ERROR; -import static gr.thmmy.mthmmy.utils.Thmmy.FAILED; -import static gr.thmmy.mthmmy.utils.Thmmy.LOGGED_IN; -import static gr.thmmy.mthmmy.utils.Thmmy.OTHER_ERROR; -import static gr.thmmy.mthmmy.utils.Thmmy.WRONG_PASSWORD; -import static gr.thmmy.mthmmy.utils.Thmmy.WRONG_USER; -import static gr.thmmy.mthmmy.utils.Thmmy.login; - public class LoginActivity extends BaseActivity { - private static final String TAG = "LoginActivity"; + +//-----------------------------------------CLASS VARIABLES------------------------------------------ + /* --Graphics-- */ private Button btnLogin; private EditText inputUsername; private EditText inputPassword; private String username; private String password; + /* --Graphics End-- */ + + //Other variables + private static final String TAG = "LoginActivity"; + @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_login); + //Variables initialization inputUsername = (EditText) findViewById(R.id.username); inputPassword = (EditText) findViewById(R.id.password); btnLogin = (Button) findViewById(R.id.btnLogin); Button btnGuest = (Button) findViewById(R.id.btnContinueAsGuest); - // Login button Click Event + //Login button Click Event btnLogin.setOnClickListener(new View.OnClickListener() { public void onClick(View view) { Log.d(TAG, "Login"); + //Get username and password strings username = inputUsername.getText().toString().trim(); password = inputPassword.getText().toString().trim(); - // Check for empty data in the form + //Check for empty data in the form if (!validate()) { onLoginFailed(); return; } - // login user + //Login user new LoginTask().execute(username, password); } }); - // Guest Button Action + //Guest Button Action btnGuest.setOnClickListener(new View.OnClickListener() { public void onClick(View view) { - SharedPreferences.Editor editor = getSharedPreferences(SHARED_PREFS_NAME, MODE_PRIVATE).edit(); - editor.putString(USER_NAME, GUEST_PREF_USERNAME); - editor.putBoolean(IS_LOGGED_IN, true); - editor.apply(); + //Session data update + _prefs.edit().putString(USER_NAME, GUEST_PREF_USERNAME).apply(); + _prefs.edit().putInt(LOG_STATUS, LOGGED_IN).apply(); + //Go to main Intent intent = new Intent(LoginActivity.this, MainActivity.class); startActivity(intent); finish(); @@ -84,11 +84,11 @@ public class LoginActivity extends BaseActivity { private void onLoginFailed() { Toast.makeText(getBaseContext(), "Login failed", Toast.LENGTH_LONG).show(); - btnLogin.setEnabled(true); } private boolean validate() { + //Handle empty text fields boolean valid = true; if (username.isEmpty()) { @@ -108,21 +108,23 @@ public class LoginActivity extends BaseActivity { return valid; } +//--------------------------------------------LOGIN------------------------------------------------- private class LoginTask extends AsyncTask { + //Class variables ProgressDialog progressDialog; @Override protected Integer doInBackground(String... params) { - setLoginData(login(params[0], params[1], "-1")); - return loginData.getStatus(); + Thmmy.login(params[0], params[1], "-1"); //Attempt login + return _prefs.getInt(LOG_STATUS, OTHER_ERROR); } @Override - protected void onPreExecute() { - btnLogin.setEnabled(false); + protected void onPreExecute() { //Show a progress dialog until done + btnLogin.setEnabled(false); //Login button shouldn't be pressed during this progressDialog = new ProgressDialog(LoginActivity.this, - R.style.AppTheme_Dark_Dialog); + R.style.AppTheme); progressDialog.setIndeterminate(true); progressDialog.setMessage("Authenticating..."); progressDialog.show(); @@ -130,7 +132,7 @@ public class LoginActivity extends BaseActivity { @Override - protected void onPostExecute(Integer result) { + protected void onPostExecute(Integer result) { //Handle attempt result switch (result) { case WRONG_USER: Toast.makeText(getApplicationContext(), @@ -156,24 +158,22 @@ public class LoginActivity extends BaseActivity { "Check your connection!", Toast.LENGTH_LONG) .show(); break; - case LOGGED_IN: - SharedPreferences.Editor editor = getSharedPreferences(SHARED_PREFS_NAME, MODE_PRIVATE).edit(); - editor.putString(USER_NAME, username); - editor.putBoolean(IS_LOGGED_IN, true); - editor.apply(); - + case LOGGED_IN: //Successful login Toast.makeText(getApplicationContext(), "Login successful!", Toast.LENGTH_LONG) .show(); + //Go to main Intent intent = new Intent(LoginActivity.this, MainActivity.class); startActivity(intent); finish(); overridePendingTransition(R.anim.push_left_in, R.anim.push_left_out); break; } - btnLogin.setEnabled(true); - progressDialog.dismiss(); + //Login failed + btnLogin.setEnabled(true); //Re-enable login button + progressDialog.dismiss(); //Hide progress dialog } } +//---------------------------------------LOGIN ENDS------------------------------------------------- } diff --git a/app/src/main/java/gr/thmmy/mthmmy/activities/MainActivity.java b/app/src/main/java/gr/thmmy/mthmmy/activities/MainActivity.java index 9f8138cf..afe564d8 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/activities/MainActivity.java +++ b/app/src/main/java/gr/thmmy/mthmmy/activities/MainActivity.java @@ -1,7 +1,7 @@ package gr.thmmy.mthmmy.activities; +import android.app.ProgressDialog; import android.content.Intent; -import android.content.SharedPreferences; import android.os.AsyncTask; import android.os.Bundle; import android.support.design.widget.TabLayout; @@ -14,16 +14,18 @@ import android.view.Menu; import android.view.MenuItem; import android.widget.Toast; +import java.util.Objects; + import gr.thmmy.mthmmy.R; import gr.thmmy.mthmmy.data.TopicSummary; import gr.thmmy.mthmmy.sections.recent.RecentFragment; -import gr.thmmy.mthmmy.utils.Thmmy; + +import static gr.thmmy.mthmmy.activities.BaseActivity.Thmmy.logout; public class MainActivity extends BaseActivity implements RecentFragment.OnListFragmentInteractionListener { - /** - * The {@link ViewPager} that will host the section contents. - */ +//----------------------------------------CLASS VARIABLES----------------------------------------- + private static final String TAG = "MainActivity"; private Menu menu; @Override @@ -31,21 +33,22 @@ public class MainActivity extends BaseActivity implements RecentFragment.OnListF super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); - SharedPreferences prefs = getSharedPreferences(SHARED_PREFS_NAME, MODE_PRIVATE); - if (!prefs.getBoolean(IS_LOGGED_IN, false)) { + if (_prefs.getInt(LOG_STATUS, OTHER_ERROR) != LOGGED_IN) { //If not logged in + //Go to login Intent intent = new Intent(MainActivity.this, LoginActivity.class); startActivity(intent); finish(); overridePendingTransition(R.anim.push_right_in, R.anim.push_right_out); } + //Initialize toolbar Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar); setSupportActionBar(toolbar); - // Create the adapter that will return a fragment for each section of the activity + //Create the adapter that will return a fragment for each section of the activity SectionsPagerAdapter mSectionsPagerAdapter = new SectionsPagerAdapter(getSupportFragmentManager()); - // Set up the ViewPager with the sections adapter. + //Set up the ViewPager with the sections adapter. ViewPager mViewPager = (ViewPager) findViewById(R.id.container); mViewPager.setAdapter(mSectionsPagerAdapter); @@ -62,14 +65,16 @@ public class MainActivity extends BaseActivity implements RecentFragment.OnListF @Override public boolean onCreateOptionsMenu(Menu menu) { - // Inflate the menu; this adds items to the action bar if it is present. + //Inflate the menu; this adds items to the action bar if it is present. this.menu = menu; getMenuInflater().inflate(R.menu.menu_main, menu); - SharedPreferences prefs = getSharedPreferences(SHARED_PREFS_NAME, MODE_PRIVATE); - if (prefs.getBoolean(IS_LOGGED_IN, false) - && prefs.getString(USER_NAME, null) != GUEST_PREF_USERNAME) + + if (_prefs.getInt(LOG_STATUS, OTHER_ERROR) == LOGGED_IN + && !Objects.equals(_prefs.getString(USER_NAME, null), GUEST_PREF_USERNAME)) { + //Will enter when logged out or if user is guest hideLogin(); - else + } else + //Will enter when logged in hideLogout(); return true; @@ -80,12 +85,15 @@ public class MainActivity extends BaseActivity implements RecentFragment.OnListF int id = item.getItemId(); if (id == R.id.action_about) { + //Go to about Intent i = new Intent(MainActivity.this, AboutActivity.class); startActivity(i); return true; } else if (id == R.id.action_logout) + //Attempt logout new LogoutTask().execute(); else { + //Go to login Intent intent = new Intent(MainActivity.this, LoginActivity.class); startActivity(intent); finish(); @@ -95,14 +103,14 @@ public class MainActivity extends BaseActivity implements RecentFragment.OnListF return super.onOptionsItemSelected(item); } - private void hideLogin() { + private void hideLogin() { //Hide login AND show logout MenuItem login = menu.findItem(R.id.action_login); MenuItem logout = menu.findItem(R.id.action_logout); login.setVisible(false); logout.setVisible(true); } - private void hideLogout() { + private void hideLogout() { //Hide logout AND show login MenuItem login = menu.findItem(R.id.action_login); MenuItem logout = menu.findItem(R.id.action_logout); login.setVisible(true); @@ -156,27 +164,37 @@ public class MainActivity extends BaseActivity implements RecentFragment.OnListF return null; } } +//-------------------------------FragmentPagerAdapter END------------------------------------------- + +//-------------------------------------------LOGOUT------------------------------------------------- + private class LogoutTask extends AsyncTask { //Attempt logout + ProgressDialog progressDialog; - private class LogoutTask extends AsyncTask { protected Integer doInBackground(Void... voids) { - return Thmmy.logout(loginData); + return logout(); } - protected void onPreExecute() { - //TODO: a progressbar maybe? + protected void onPreExecute() { //Show a progress dialog until done + progressDialog = new ProgressDialog(MainActivity.this, + R.style.AppTheme); + progressDialog.setIndeterminate(true); + progressDialog.setMessage("Logging out..."); + progressDialog.show(); } - protected void onPostExecute(Integer result) { - if (result == Thmmy.LOGGED_OUT) { - SharedPreferences.Editor editor = getSharedPreferences(SHARED_PREFS_NAME, MODE_PRIVATE).edit(); - editor.putString(USER_NAME, null); - editor.putBoolean(IS_LOGGED_IN, false); - editor.apply(); + protected void onPostExecute(Integer result) { //Handle attempt result + progressDialog.dismiss(); //Hide progress dialog + if (result == LOGGED_OUT) { //Successful logout + /* + At this point result is LOGGED_OUT + BUT pref's LOGIN_STATUS variable is LOGGED_IN!! + and USER_NAME is GUEST + */ Toast.makeText(getBaseContext(), "Logged out successfully!", Toast.LENGTH_LONG).show(); - hideLogout(); - } else + } else //Logout failed hideLogin(); } } -} +//-----------------------------------------LOGOUT END----------------------------------------------- +} \ No newline at end of file diff --git a/app/src/main/java/gr/thmmy/mthmmy/activities/TopicActivity.java b/app/src/main/java/gr/thmmy/mthmmy/activities/TopicActivity.java index 725ccb61..c496e30e 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/activities/TopicActivity.java +++ b/app/src/main/java/gr/thmmy/mthmmy/activities/TopicActivity.java @@ -39,16 +39,29 @@ import okhttp3.Request; import okhttp3.Response; public class TopicActivity extends BaseActivity { - private static final int THUMBNAIL_SIZE = 80; - private final SparseArray pagesUrls = new SparseArray<>(); - private ImageLoader imageLoader = ImageController.getInstance().getImageLoader(); - private ProgressBar progressBar; + +//-----------------------------------------CLASS VARIABLES------------------------------------------ + + /* --Post-- */ private List postsList; - private EditText pageSelect; private LinearLayout postsLinearLayout; + /* --Topic's page-- */ private int thisPage = 1; private String base_url = ""; private int numberOfPages = 1; + private EditText pageSelect; + private final SparseArray pagesUrls = new SparseArray<>(); + /* --Topic's page end-- */ + /* --Thumbnail-- */ + private static final int THUMBNAIL_SIZE = 80; + private ImageLoader imageLoader = ImageController.getInstance().getImageLoader(); + /* --Thumbnail end-- */ + + //Other variables + private ProgressBar progressBar; + private static final String TAG = "TopicActivity"; + + @Override protected void onCreate(Bundle savedInstanceState) { @@ -58,6 +71,7 @@ public class TopicActivity extends BaseActivity { Bundle extras = getIntent().getExtras(); final String topicTitle = getIntent().getExtras().getString("TOPIC_TITLE"); + //Variables initialization postsLinearLayout = (LinearLayout) findViewById(R.id.posts_list); progressBar = (ProgressBar) findViewById(R.id.progressBar); @@ -65,32 +79,39 @@ public class TopicActivity extends BaseActivity { if (imageLoader == null) imageLoader = ImageController.getInstance().getImageLoader(); + postsList = new ArrayList<>(); + ActionBar actionbar = getSupportActionBar(); if (actionbar != null) actionbar.setTitle(topicTitle); + /* Add page select field to the Action Bar */ + //Edit Action Bar's parameters ActionBar.LayoutParams lp = new ActionBar.LayoutParams( LinearLayout.LayoutParams.WRAP_CONTENT , LinearLayout.LayoutParams.WRAP_CONTENT , Gravity.END | Gravity.CENTER_VERTICAL); + //Initialize layout to be added View customNav = LayoutInflater.from(this).inflate(R.layout.topic_page_select, null); - + //Initialize text field pageSelect = (EditText) customNav.findViewById(R.id.select_page); pageSelect.setOnEditorActionListener(new TextView.OnEditorActionListener() { @Override - public boolean onEditorAction(TextView v, int actionId, KeyEvent event) { + public boolean onEditorAction(TextView v, int actionId, KeyEvent event) { //When page is changed if (actionId == EditorInfo.IME_ACTION_GO) { + //Get page requested by user int pageRequested = Integer.parseInt(pageSelect.getText().toString()); if (pageRequested == thisPage) { Toast.makeText(getBaseContext() , "You already are here!", Toast.LENGTH_LONG).show(); } else if (pageRequested >= 1 && pageRequested <= numberOfPages) { + //Restart activity with new page Intent intent = getIntent(); intent.putExtra("TOPIC_URL", pagesUrls.get(pageRequested - 1)); intent.putExtra("TOPIC_TITLE", topicTitle); finish(); startActivity(intent); - } else { + } else { //Invalid page request Toast.makeText(getBaseContext() , "There is no such page!", Toast.LENGTH_LONG).show(); } @@ -99,171 +120,190 @@ public class TopicActivity extends BaseActivity { } }); assert actionbar != null; - actionbar.setCustomView(customNav, lp); + actionbar.setCustomView(customNav, lp); //Add feature to Action Bar actionbar.setDisplayShowCustomEnabled(true); - postsList = new ArrayList<>(); - new TopicTask().execute(extras.getString("TOPIC_URL")); + new TopicTask().execute(extras.getString("TOPIC_URL")); //Attempt data parsing } @Override - protected void onDestroy() { + protected void onDestroy() { //When finished cancel whatever request can still be canceled super.onDestroy(); ImageController.getInstance().cancelPendingRequests(); } //---------------------------------------TOPIC ASYNC TASK------------------------------------------- - - private void populateLayout() { - LayoutInflater inflater = (LayoutInflater) getApplicationContext() - .getSystemService(Context.LAYOUT_INFLATER_SERVICE); - - for (Post item : postsList) { - View convertView = inflater.inflate(R.layout.activity_topic_post_row - , postsLinearLayout, false); - - if (imageLoader == null) - imageLoader = ImageController.getInstance().getImageLoader(); - - CircularNetworkImageView thumbnail = (CircularNetworkImageView) convertView.findViewById(R.id.thumbnail); - TextView username = (TextView) convertView.findViewById(R.id.username); - TextView postNum = (TextView) convertView.findViewById(R.id.post_number); - TextView subject = (TextView) convertView.findViewById(R.id.subject); - WebView post = (WebView) convertView.findViewById(R.id.post); - - //Avoiding errors about layout having 0 width/height - thumbnail.setMinimumWidth(1); - thumbnail.setMinimumHeight(1); - //Set thumbnail size - thumbnail.setMaxWidth(THUMBNAIL_SIZE); - thumbnail.setMaxHeight(THUMBNAIL_SIZE); - - // thumbnail image - if (item.getThumbnailUrl() != null) { - thumbnail.setImageUrl(item.getThumbnailUrl(), imageLoader); - } - - username.setText(item.getAuthor()); - if (item.getPostNumber() != 0) - postNum.setText("#" + item.getPostNumber()); - subject.setText(item.getSubject()); - post.loadDataWithBaseURL("file:///android_asset/", item.getContent(), "text/html", "UTF-8", null); - post.setEnabled(false); - postsLinearLayout.addView(convertView); - } - } - public class TopicTask extends AsyncTask { - private static final String TAG = "TopicTask"; - private String pageLink; - private Document document; + //Class variables + private static final String TAG = "TopicTask"; //Separate tag for AsyncTask + //Show a progress bar until done protected void onPreExecute() { progressBar.setVisibility(ProgressBar.VISIBLE); } protected Boolean doInBackground(String... strings) { - base_url = strings[0].substring(0, strings[0].lastIndexOf(".")); - - pageLink = strings[0]; + Document document; + base_url = strings[0].substring(0, strings[0].lastIndexOf(".")); //This topic's base url + String pageLink = strings[0]; //This page's url Request request = new Request.Builder() .url(pageLink) .build(); - try { Response response = client.newCall(request).execute(); document = Jsoup.parse(response.body().string()); - return parse(document); + parse(document); //Parse data + return true; } 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; } + return false; } protected void onPostExecute(Boolean result) { - progressBar.setVisibility(ProgressBar.INVISIBLE); - populateLayout(); + if (!result) { //Parse failed! + //Should never happen + Toast.makeText(getBaseContext() + , "Fatal error!\n Aborting...", Toast.LENGTH_LONG).show(); + finish(); + } + //Parse was successful + progressBar.setVisibility(ProgressBar.INVISIBLE); //Hide progress bar + populateLayout(); //Show parsed data + //Set current page pageSelect.setHint(String.valueOf(thisPage) + "/" + String.valueOf(numberOfPages)); } - private boolean parse(Document document) { - { - Elements findCurrentPage = document.select("td:contains(Pages:)>b"); + /* Parse method */ + private void parse(Document document) { + { //Find current page's index + Elements findCurrentPage = document.select("td:contains(Pages:)>b"); //Contains pages for (Element item : findCurrentPage) { - if (!item.text().contains("...") - && !item.text().contains("Pages")) { + if (!item.text().contains("...") //It's not "..." + && !item.text().contains("Pages")) { //Nor "Pages" thisPage = Integer.parseInt(item.text()); break; } } } - { - Elements footer_pages = document.select("td:contains(Pages:)>a.navPages"); - if (footer_pages.size() != 0) { - numberOfPages = thisPage; - for (Element item : footer_pages) { + { //Find number of pages + Elements pages = document.select("td:contains(Pages:)>a.navPages"); //Contains all pages + if (pages.size() != 0) { + numberOfPages = thisPage; //Initialize the number + for (Element item : pages) { //Just a max if (Integer.parseInt(item.text()) > numberOfPages) numberOfPages = Integer.parseInt(item.text()); } } for (int i = 0; i < numberOfPages; i++) { + //Generate each page's url from topic's base url +".15*numberOfPage" pagesUrls.put(i, base_url + "." + String.valueOf(i * 15)); } } - //Each element is a post row + //Each element is a post's row Elements rows = document.select("form[id=quickModForm]>table>tbody>tr:matches(on)"); - for (Element item: rows) { //For every post + for (Element item : rows) { //For every post + //Variables to pass String p_userName, p_thumbnailUrl, p_subject, p_post; int p_postNum; //Find the Username Element userName = item.select("a[title^=View the profile of]").first(); - if(userName == null){ //Deleted profile + if (userName == null) { //Deleted profile p_userName = item .select("td:has(div.smalltext:containsOwn(Guest))[style^=overflow]") .first().text(); p_userName = p_userName.substring(0, p_userName.indexOf(" Guest")); - } - else + } else p_userName = userName.html(); //Find thumbnail url Element thumbnailUrl = item.select("img.avatar").first(); p_thumbnailUrl = null; //In case user doesn't have an avatar - if(thumbnailUrl != null){ + if (thumbnailUrl != null) { p_thumbnailUrl = thumbnailUrl.attr("abs:src"); } //Find subject p_subject = item.select("div[id^=subject_]").first().select("a").first().text(); - //Find post's text p_post = item.select("div").select(".post").first().html(); + //Add stuff to make it work in WebView p_post = ("" + p_post); //style.css //Find post's index number Element postNum = item.select("div.smalltext:matches(Reply #)").first(); - if(postNum == null){ //Topic starter + if (postNum == null) { //Topic starter p_postNum = 0; - } - else{ + } else { String tmp_str = postNum.text().substring(9); p_postNum = Integer.parseInt(tmp_str.substring(0, tmp_str.indexOf(" on"))); } + //Add new post in postsList postsList.add(new Post(p_thumbnailUrl, p_userName, p_subject , p_post, p_postNum)); } - return true; + } + /* Parse method end */ + } +//-------------------------------------TOPIC ASYNC TASK END----------------------------------------- + + private void populateLayout() { //Show parsed data + //Initialize an inflater + LayoutInflater inflater = (LayoutInflater) getApplicationContext() + .getSystemService(Context.LAYOUT_INFLATER_SERVICE); + + for (Post item : postsList) { + //Inflate a topic post row layout + View convertView = inflater.inflate(R.layout.activity_topic_post_row + , postsLinearLayout, false); + + if (imageLoader == null) + imageLoader = ImageController.getInstance().getImageLoader(); + + //Initialize layout's graphic elements + CircularNetworkImageView thumbnail = (CircularNetworkImageView) convertView.findViewById(R.id.thumbnail); + TextView username = (TextView) convertView.findViewById(R.id.username); + TextView postNum = (TextView) convertView.findViewById(R.id.post_number); + TextView subject = (TextView) convertView.findViewById(R.id.subject); + WebView post = (WebView) convertView.findViewById(R.id.post); + + //Avoiding errors about layout having 0 width/height + thumbnail.setMinimumWidth(1); + thumbnail.setMinimumHeight(1); + //Set thumbnail size + thumbnail.setMaxWidth(THUMBNAIL_SIZE); + thumbnail.setMaxHeight(THUMBNAIL_SIZE); + + //Thumbnail image set + if (item.getThumbnailUrl() != null) { + thumbnail.setImageUrl(item.getThumbnailUrl(), imageLoader); + } + + //Username set + username.setText(item.getAuthor()); + + //Post's index number set + if (item.getPostNumber() != 0) + postNum.setText("#" + item.getPostNumber()); + + //Subject set + subject.setText(item.getSubject()); + + //Post's text set + post.loadDataWithBaseURL("file:///android_asset/", item.getContent(), "text/html", "UTF-8", null); + post.setEnabled(false); + + //Add view to the linear layout that holds all posts + postsLinearLayout.addView(convertView); } } } diff --git a/app/src/main/java/gr/thmmy/mthmmy/data/Post.java b/app/src/main/java/gr/thmmy/mthmmy/data/Post.java index d2f375f7..edf8d58c 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/data/Post.java +++ b/app/src/main/java/gr/thmmy/mthmmy/data/Post.java @@ -1,7 +1,6 @@ package gr.thmmy.mthmmy.data; -public class Post -{ +public class Post { private final String thumbnailUrl; private final String author; private final String subject; @@ -16,7 +15,9 @@ public class Post this.postNumber = postNumber; } - public String getThumbnailUrl() { return thumbnailUrl;} + public String getThumbnailUrl() { + return thumbnailUrl; + } public String getContent() { return content; @@ -30,5 +31,7 @@ public class Post return subject; } - public int getPostNumber(){ return postNumber;} + public int getPostNumber() { + return postNumber; + } } diff --git a/app/src/main/java/gr/thmmy/mthmmy/data/TopicSummary.java b/app/src/main/java/gr/thmmy/mthmmy/data/TopicSummary.java index 0bb05c6d..935af6b1 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/data/TopicSummary.java +++ b/app/src/main/java/gr/thmmy/mthmmy/data/TopicSummary.java @@ -1,22 +1,23 @@ package gr.thmmy.mthmmy.data; -public class TopicSummary -{ +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) - { + 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 getTopicUrl() { + return topicUrl; + } + public String getTitle() { return title; } diff --git a/app/src/main/java/gr/thmmy/mthmmy/sections/recent/RecentAdapter.java b/app/src/main/java/gr/thmmy/mthmmy/sections/recent/RecentAdapter.java index 4a542cc5..80f7fb89 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/sections/recent/RecentAdapter.java +++ b/app/src/main/java/gr/thmmy/mthmmy/sections/recent/RecentAdapter.java @@ -6,18 +6,17 @@ import android.view.View; import android.view.ViewGroup; import android.widget.TextView; +import java.util.List; + 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 -{ +public class RecentAdapter extends RecyclerView.Adapter { private final List recentList; private final RecentFragment.OnListFragmentInteractionListener mListener; @@ -35,7 +34,6 @@ public class RecentAdapter extends RecyclerView.Adapter(); - if(sectionNumber==1) //? - Log.d(TAG,"onCreate"); + if (sectionNumber == 1) //? + Log.d(TAG, "onCreate"); } @Override - public void onActivityCreated(Bundle savedInstanceState) - { + public void onActivityCreated(Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); - if(sectionNumber==1)//temp + if (sectionNumber == 1)//temp { - if(topicSummaries.isEmpty()) + if (topicSummaries.isEmpty()) new RecentTask().execute(); } - Log.d(TAG,"onActivityCreated"); + Log.d(TAG, "onActivityCreated"); } @Override public void onStart() { super.onStart(); - if(sectionNumber==1) - Log.d(TAG,"onStart"); + if (sectionNumber == 1) + Log.d(TAG, "onStart"); } @Override public void onResume() { super.onResume(); - if(sectionNumber==1) - Log.d(TAG,"onResume"); + if (sectionNumber == 1) + Log.d(TAG, "onResume"); } @Override public void onPause() { super.onPause(); - if(sectionNumber==1) - Log.d(TAG,"onPause"); + if (sectionNumber == 1) + Log.d(TAG, "onPause"); } @Override public void onStop() { super.onStop(); - if(sectionNumber==1) - Log.d(TAG,"onStop"); + if (sectionNumber == 1) + Log.d(TAG, "onStop"); } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, - Bundle savedInstanceState) - { + 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) - { + if (rootView instanceof RelativeLayout) { progressBar = (ProgressBar) rootView.findViewById(R.id.progressBar); recentAdapter = new RecentAdapter(topicSummaries, mListener); @@ -206,9 +200,8 @@ public class RecentFragment extends Fragment //---------------------------------------ASYNC TASK----------------------------------- - public class RecentTask extends AsyncTask - { - private static final String TAG="RecentTask"; + public class RecentTask extends AsyncTask { + private static final String TAG = "RecentTask"; private final String thmmyUrl = "https://www.thmmy.gr/smf/index.php"; private Document document; @@ -219,8 +212,7 @@ public class RecentFragment extends Fragment progressBar.setVisibility(ProgressBar.VISIBLE); } - protected Integer doInBackground(Void... voids) - { + protected Integer doInBackground(Void... voids) { Request request = new Request.Builder() .url(thmmyUrl) @@ -231,7 +223,7 @@ public class RecentFragment extends Fragment parse(document); return 0; } catch (IOException e) { - Log.d("DEB", "ERROR", e); + Log.d("DEB", "ERROR", e); return 1; } catch (Exception e) { Log.d("DEB", "ERROR", e); @@ -241,27 +233,23 @@ public class RecentFragment extends Fragment } + protected void onPostExecute(Integer result) { - protected void onPostExecute(Integer result) - { - - if(result==0) + if (result == 0) recentAdapter.notifyDataSetChanged(); - else if (result==1) + 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) - { + private void parse(Document document) { Elements recent = document.select("#block8 :first-child div"); - if(recent.size()==30) - { + if (recent.size() == 30) { topicSummaries.clear(); - for(int i=0; iAlso constrains the circle to the leftmost part of the image - * - * @param bitmap - * @return bitmap */ private Bitmap getCircularBitmap(Bitmap bitmap) { bitmap = Bitmap.createScaledBitmap(bitmap, THUMBNAIL_SIZE, THUMBNAIL_SIZE, false); @@ -54,7 +51,7 @@ public class CircularNetworkImageView extends NetworkImageView { bitmap.getHeight(), Config.ARGB_8888); Canvas canvas = new Canvas(output); int size = bitmap.getWidth(); - if(bitmap.getWidth()>bitmap.getHeight()) + if (bitmap.getWidth() > bitmap.getHeight()) size = bitmap.getHeight(); final int color = 0xff424242; final Paint paint = new Paint(); diff --git a/app/src/main/java/gr/thmmy/mthmmy/utils/CustomRecyclerView.java b/app/src/main/java/gr/thmmy/mthmmy/utils/CustomRecyclerView.java index a6a1506c..af29a9bd 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/utils/CustomRecyclerView.java +++ b/app/src/main/java/gr/thmmy/mthmmy/utils/CustomRecyclerView.java @@ -8,7 +8,7 @@ import android.util.AttributeSet; //Custom RecyclerView, so EdgeEffect and SwipeRefresh both work public class CustomRecyclerView extends RecyclerView { - private volatile boolean enableRefreshing=true; + private volatile boolean enableRefreshing = true; public CustomRecyclerView(Context context) { super(context); @@ -24,22 +24,20 @@ public class CustomRecyclerView extends RecyclerView { @Override public void onScrolled(int dx, int dy) { - if(dy>0) - enableRefreshing=false; + 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; - + 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); @@ -47,7 +45,7 @@ public class CustomRecyclerView extends RecyclerView { @Override public boolean dispatchNestedScroll(int dxConsumed, int dyConsumed, int dxUnconsumed, int dyUnconsumed, int[] offsetInWindow) { - if(enableRefreshing) + if (enableRefreshing) return super.dispatchNestedScroll(dxConsumed, dyConsumed, dxUnconsumed, dyUnconsumed, offsetInWindow); else return super.dispatchNestedScroll(dxConsumed, dyConsumed, dxUnconsumed, 0, offsetInWindow); diff --git a/app/src/main/java/gr/thmmy/mthmmy/utils/ImageController.java b/app/src/main/java/gr/thmmy/mthmmy/utils/ImageController.java index 8eaf7045..e88350a6 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/utils/ImageController.java +++ b/app/src/main/java/gr/thmmy/mthmmy/utils/ImageController.java @@ -53,7 +53,7 @@ public class ImageController extends Application { getRequestQueue().add(req); } - public void cancelPendingRequests(){ + public void cancelPendingRequests() { mRequestQueue.cancelAll(new RequestQueue.RequestFilter() { @Override public boolean apply(Request request) { diff --git a/app/src/main/java/gr/thmmy/mthmmy/utils/LruBitmapCache.java b/app/src/main/java/gr/thmmy/mthmmy/utils/LruBitmapCache.java index 330c2e45..32ae5971 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/utils/LruBitmapCache.java +++ b/app/src/main/java/gr/thmmy/mthmmy/utils/LruBitmapCache.java @@ -9,11 +9,11 @@ class LruBitmapCache extends LruCache implements ImageCache { private static final int CACHE_SIZE_DIVIDER = 8; - LruBitmapCache() { + LruBitmapCache() { this(getDefaultLruCacheSize()); } - private LruBitmapCache(int sizeInKiloBytes) { + private LruBitmapCache(int sizeInKiloBytes) { super(sizeInKiloBytes); } diff --git a/app/src/main/java/gr/thmmy/mthmmy/utils/Thmmy.java b/app/src/main/java/gr/thmmy/mthmmy/utils/Thmmy.java deleted file mode 100644 index 553fc0f4..00000000 --- a/app/src/main/java/gr/thmmy/mthmmy/utils/Thmmy.java +++ /dev/null @@ -1,249 +0,0 @@ -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 { - public static final int LOGGED_OUT = 0; - public static final int LOGGED_IN = 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; - private static final HttpUrl loginUrl = HttpUrl.parse("https://www.thmmy.gr/smf/index.php?action=login2"); - - //-------------------------------------------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 = BaseActivity.getClient(); - - 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(LOGGED_IN); - } 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; - } - - private static void setPersistentCookieSession() { - List 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); - } - } - } - - //--------------------------------------LOGOUT-------------------------------------------------- - public static int logout(LoginData loginData) { - OkHttpClient client = BaseActivity.getClient(); - Request request = new Request.Builder() - .url(loginData.getLogoutLink()) - .build(); - - try { - Response response = client.newCall(request).execute(); - Document document = Jsoup.parse(response.body().string()); - - Elements login = document.select("[value=Login]"); - ((PersistentCookieJar) BaseActivity.getCookieJar()).clear(); - if (!login.isEmpty()) { - Log.i("Logout", "Logout successful"); - loginData.setStatus(LOGGED_OUT); - return LOGGED_OUT; - } 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; - } - - - } - //-------------------------------------LOGIN ENDS----------------------------------------------- - - //-------------------------------------------MISC--------------------------------------------------- - private 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; - } - - -//----------------------------------------LOGOUT ENDS----------------------------------------------- - - //To maintain data between activities/ between activity state change (possibly temporary solution) - public static class LoginData implements Parcelable { - public static final Parcelable.Creator CREATOR - = new Parcelable.Creator() { - public LoginData createFromParcel(Parcel in) { - return new LoginData(in); - } - - public LoginData[] newArray(int size) { - return new LoginData[size]; - } - }; - private int status; - private String username; - private HttpUrl logoutLink; - - public LoginData() { - } - - private LoginData(Parcel in) { - status = in.readInt(); - username = in.readString(); - logoutLink = HttpUrl.parse(in.readString()); - } - - public String getUsername() { - return username; - } - - void setUsername(String username) { - this.username = username; - } - - public int getStatus() { - return status; - } - - public void setStatus(int status) { - this.status = status; - } - - HttpUrl getLogoutLink() { - return logoutLink; - } - - 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()); - } - } - -} diff --git a/app/src/main/res/anim/push_left_in.xml b/app/src/main/res/anim/push_left_in.xml index 6ac5724d..3ce7b680 100644 --- a/app/src/main/res/anim/push_left_in.xml +++ b/app/src/main/res/anim/push_left_in.xml @@ -1,8 +1,8 @@ - + \ No newline at end of file diff --git a/app/src/main/res/anim/push_left_out.xml b/app/src/main/res/anim/push_left_out.xml index 923cad88..10d90e29 100644 --- a/app/src/main/res/anim/push_left_out.xml +++ b/app/src/main/res/anim/push_left_out.xml @@ -1,7 +1,7 @@ - + \ No newline at end of file diff --git a/app/src/main/res/anim/push_right_in.xml b/app/src/main/res/anim/push_right_in.xml index 6b4cdf8d..0aee10cc 100644 --- a/app/src/main/res/anim/push_right_in.xml +++ b/app/src/main/res/anim/push_right_in.xml @@ -3,6 +3,6 @@ + android:toXDelta="0"/> \ No newline at end of file diff --git a/app/src/main/res/anim/push_right_out.xml b/app/src/main/res/anim/push_right_out.xml index 1d45e3b5..0221bc4c 100644 --- a/app/src/main/res/anim/push_right_out.xml +++ b/app/src/main/res/anim/push_right_out.xml @@ -3,6 +3,6 @@ + android:toXDelta="100%p"/> \ No newline at end of file diff --git a/app/src/main/res/layout/activity_login.xml b/app/src/main/res/layout/activity_login.xml index 278fbdc0..60b7fe76 100644 --- a/app/src/main/res/layout/activity_login.xml +++ b/app/src/main/res/layout/activity_login.xml @@ -14,7 +14,7 @@ + android:layout_height="25dp"/> + android:layout_height="10dp"/> @@ -60,12 +57,10 @@ android:layout_height="wrap_content" android:layout_alignParentTop="true" android:layout_marginEnd="5dp" - android:layout_marginRight="5dp" android:layout_toEndOf="@+id/thumbnail_holder" - android:layout_toRightOf="@+id/thumbnail_holder" android:ellipsize="end" android:maxLines="1" - android:text="sometext" + android:text="@string/username" android:textColor="@color/black" android:textStyle="bold"/> @@ -74,10 +69,7 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentEnd="true" - android:layout_alignParentRight="true" android:layout_alignParentTop="true" - android:layout_marginLeft="100dp" - android:layout_marginStart="100dp" android:text=""/> @@ -114,7 +105,7 @@ android:layout_marginLeft="8dp" android:layout_marginRight="8dp" android:background="@color/white" - android:text="sometext" + android:text="@string/post" /> diff --git a/app/src/main/res/layout/fragment_recent_row.xml b/app/src/main/res/layout/fragment_recent_row.xml index 8c62b89e..2d61f25c 100644 --- a/app/src/main/res/layout/fragment_recent_row.xml +++ b/app/src/main/res/layout/fragment_recent_row.xml @@ -31,7 +31,6 @@ android:id="@+id/title" android:layout_width="match_parent" android:layout_height="wrap_content" - android:layout_alignParentLeft="true" android:layout_alignParentStart="true" android:layout_alignParentTop="true" android:textAppearance="?attr/textAppearanceListItem" @@ -43,14 +42,12 @@ android:layout_height="20dp" android:layout_alignParentBottom="@+id/title" android:layout_below="@+id/title" - android:layout_toEndOf="@+id/dateTime" - android:layout_toRightOf="@+id/dateTime"/> + android:layout_toEndOf="@+id/dateTime"/> @@ -61,7 +58,6 @@ android:layout_alignBaseline="@+id/dateTime" android:layout_alignBottom="@+id/dateTime" android:layout_alignParentEnd="true" - android:layout_alignParentRight="true" android:textStyle="italic"/> diff --git a/app/src/main/res/menu/menu_main.xml b/app/src/main/res/menu/menu_main.xml index 7e6293a2..515a9f73 100644 --- a/app/src/main/res/menu/menu_main.xml +++ b/app/src/main/res/menu/menu_main.xml @@ -1,22 +1,22 @@ + xmlns:app="http://schemas.android.com/apk/res-auto" + xmlns:tools="http://schemas.android.com/tools" + tools:context=".activities.MainActivity"> + app:showAsAction="never"/> + app:showAsAction="never"/> + app:showAsAction="never"/> diff --git a/app/src/main/res/values/dimens.xml b/app/src/main/res/values/dimens.xml index fea32b5f..5e067b76 100644 --- a/app/src/main/res/values/dimens.xml +++ b/app/src/main/res/values/dimens.xml @@ -2,7 +2,6 @@ 16dp 16dp - 16dp 8dp 80dp diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 4f89287c..6438e9e8 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -1,7 +1,5 @@ mTHMMY - Settings - Hello World from section: %1$d thmmy.gr Username @@ -12,7 +10,10 @@ About v%1$s logo - Name Login Logout + + Username should be here... + Subject should be here... + Post should be here...