fix event info hiding after activity restore (closes #23), add comments

This commit is contained in:
akaessens 2020-10-03 20:12:24 +02:00
parent ce790763fd
commit 9e81e3d74a
7 changed files with 114 additions and 52 deletions

View File

@ -60,6 +60,10 @@ public class EventAdapter extends
// Set item views based on your views and data model // Set item views based on your views and data model
holder.text_view_event_name.setText(event.name); holder.text_view_event_name.setText(event.name);
/*
* initialize all text views with event information
* hide fields and image views if no information is available
*/
if (!event.location.equals("")) { if (!event.location.equals("")) {
holder.text_view_event_location.setText(event.location); holder.text_view_event_location.setText(event.location);
} else { } else {
@ -86,7 +90,6 @@ public class EventAdapter extends
} }
if (!event.description.equals("")) { if (!event.description.equals("")) {
holder.text_view_event_description.setText(event.description); holder.text_view_event_description.setText(event.description);
} else { } else {
@ -120,13 +123,14 @@ public class EventAdapter extends
}; };
holder.image_view_event_location.setOnClickListener(location_click_listener); holder.image_view_event_location.setOnClickListener(location_click_listener);
holder.text_view_event_location.setOnClickListener(location_click_listener); holder.text_view_event_location.setOnClickListener(location_click_listener);
/* /*
* Add to calendar button: launch calendar application with current event * Add to calendar button: launch calendar application with current event
*/ */
holder.button_add_to_calendar.setOnClickListener(new View.OnClickListener() { holder.button_add_to_calendar.setOnClickListener(new View.OnClickListener() {
@Override @Override
public void onClick(View view) { public void onClick(View view) {
// calendar event intent expects epoch time format
Long start_epoch = dateTimeToEpoch(event.start_date); Long start_epoch = dateTimeToEpoch(event.start_date);
Long end_epoch = dateTimeToEpoch(event.end_date); Long end_epoch = dateTimeToEpoch(event.end_date);
@ -163,7 +167,7 @@ public class EventAdapter extends
}); });
/* /*
* Image dialog * Image preview click creates fullscreen dialog
*/ */
View.OnClickListener listener = new View.OnClickListener() { View.OnClickListener listener = new View.OnClickListener() {
@ -198,7 +202,6 @@ public class EventAdapter extends
}); });
} }
}; };
holder.image_view_event_image.setOnClickListener(listener); holder.image_view_event_image.setOnClickListener(listener);
@ -212,6 +215,9 @@ public class EventAdapter extends
return events.size(); return events.size();
} }
/**
* access item view elements via holder class
*/
public static class ViewHolder extends RecyclerView.ViewHolder { public static class ViewHolder extends RecyclerView.ViewHolder {
protected TextView text_view_event_name; protected TextView text_view_event_name;

View File

@ -163,6 +163,7 @@ public class FbEventScraper extends AsyncTask<Void, Void, Void> {
JSONObject reader = new JSONObject(json); JSONObject reader = new JSONObject(json);
// get all fields from json event information
name = readFromJson(reader, "name"); name = readFromJson(reader, "name");
start_date = parseToDate(readFromJson(reader, "startDate")); start_date = parseToDate(readFromJson(reader, "startDate"));
end_date = parseToDate(readFromJson(reader, "endDate")); end_date = parseToDate(readFromJson(reader, "endDate"));
@ -170,6 +171,7 @@ public class FbEventScraper extends AsyncTask<Void, Void, Void> {
location = fixLocation(readFromJson(reader, "location")); location = fixLocation(readFromJson(reader, "location"));
image_url = readFromJson(reader, "image"); image_url = readFromJson(reader, "image");
// try to find a high-res image
try { try {
image_url = document.select("div[id=event_header_primary]") image_url = document.select("div[id=event_header_primary]")
.select("img").first().attr("src"); .select("img").first().attr("src");
@ -177,6 +179,7 @@ public class FbEventScraper extends AsyncTask<Void, Void, Void> {
} }
} catch (JSONException | NullPointerException e) { } catch (JSONException | NullPointerException e) {
// json event information mot found. get at least title and image
name = document.title(); name = document.title();
description = scraper.main.get().getString(R.string.error_scraping); description = scraper.main.get().getString(R.string.error_scraping);
try { try {
@ -186,9 +189,6 @@ public class FbEventScraper extends AsyncTask<Void, Void, Void> {
} }
} }
this.event = new FbEvent(url, name, start_date, end_date, description, location, image_url); this.event = new FbEvent(url, name, start_date, end_date, description, location, image_url);
} catch (IOException e) { } catch (IOException e) {

View File

@ -22,7 +22,7 @@ public class FbPageScraper extends AsyncTask<Void, Void, Void> {
private FbScraper scraper; private FbScraper scraper;
private int error; private int error;
private String url; private String url;
private List<String> event_links = new ArrayList<String>(); private List<String> event_links = new ArrayList<>();
/** /**
* Constructor with reference to scraper to return results. * Constructor with reference to scraper to return results.
@ -58,6 +58,9 @@ public class FbPageScraper extends AsyncTask<Void, Void, Void> {
throw new IOException(); throw new IOException();
} }
/*
* get all event id's from current url and add to the list
*/
String regex = "(/events/[0-9]*)(/\\?event_time_id=[0-9]*)?"; String regex = "(/events/[0-9]*)(/\\?event_time_id=[0-9]*)?";
List<String> event_links_href = document List<String> event_links_href = document
@ -68,13 +71,16 @@ public class FbPageScraper extends AsyncTask<Void, Void, Void> {
this.event_links.add("https://www.facebook.com" + link); this.event_links.add("https://www.facebook.com" + link);
} }
/*
* check if more events should scraped
*/
SharedPreferences shared_prefs = PreferenceManager SharedPreferences shared_prefs = PreferenceManager
.getDefaultSharedPreferences(scraper.main.get()); .getDefaultSharedPreferences(scraper.main.get());
int max = shared_prefs.getInt("page_event_max", 5); int max = shared_prefs.getInt("page_event_max", 5);
if (event_links.size() < max) { if (event_links.size() < max) {
// find "next page
try { try {
String next_url = document String next_url = document
.getElementsByAttributeValueMatching("href", "has_more=1") .getElementsByAttributeValueMatching("href", "has_more=1")

View File

@ -14,15 +14,12 @@ import java.util.List;
import java.util.regex.Matcher; import java.util.regex.Matcher;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import static com.akdev.nofbeventscraper.FbEvent.createEventList;
public class FbScraper { public class FbScraper {
protected List<FbEvent> events;
protected List<AsyncTask> tasks; protected List<AsyncTask> tasks;
protected WeakReference<MainActivity> main; // no context leak with WeakReference
url_type_enum url_type = url_type_enum.EVENT; url_type_enum url_type = url_type_enum.EVENT;
private String input_url; private String input_url;
protected WeakReference<MainActivity> main; // no context leak with WeakReference
/** /**
* Constructor with WeakReference to the main activity, to add events. * Constructor with WeakReference to the main activity, to add events.
@ -33,10 +30,18 @@ public class FbScraper {
FbScraper(WeakReference<MainActivity> main, String input_url) { FbScraper(WeakReference<MainActivity> main, String input_url) {
this.main = main; this.main = main;
this.input_url = input_url; this.input_url = input_url;
this.events = createEventList();
this.tasks = new ArrayList<>(); this.tasks = new ArrayList<>();
} }
/**
* Checks if valid URL,
* strips the facebook page id from the input link and create an URL that can be scraped from.
*
* @param url input URL
* @return new mbasic url that can be scraped for event id's
* @throws URISyntaxException if page not found
* @throws MalformedURLException
*/
protected String getPageUrl(String url) throws URISyntaxException, MalformedURLException { protected String getPageUrl(String url) throws URISyntaxException, MalformedURLException {
// check for url format // check for url format
@ -48,10 +53,11 @@ public class FbScraper {
Matcher matcher = pattern.matcher(url); Matcher matcher = pattern.matcher(url);
if (matcher.find()) { if (matcher.find()) {
//only mbasic does have event ids displayed in HTML
String url_prefix = "https://mbasic.facebook.com/"; String url_prefix = "https://mbasic.facebook.com/";
String url_suffix = "?v=events"; String url_suffix = "?v=events";
// create URL
return url_prefix + matcher.group(3) + url_suffix; return url_prefix + matcher.group(3) + url_suffix;
} else { } else {
@ -60,7 +66,7 @@ public class FbScraper {
} }
/** /**
* Strips the facebook event link of the input url. * Strips the facebook event link from the input event url.
* *
* @param url input url * @param url input url
* @return facebook event url String if one was found * @return facebook event url String if one was found
@ -98,12 +104,40 @@ public class FbScraper {
} }
/**
* cancel vestigial async tasks
*/
void killAllTasks() {
if (!tasks.isEmpty()) {
for (AsyncTask task : tasks) {
try {
task.cancel(true);
task = null;
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
/**
* start an EventScraper async task and add to tasks list
*
* @param event_url
*/
void scrapeEvent(String event_url) { void scrapeEvent(String event_url) {
FbEventScraper scraper = new FbEventScraper(this, event_url); FbEventScraper scraper = new FbEventScraper(this, event_url);
tasks.add(scraper); tasks.add(scraper);
scraper.execute(); scraper.execute();
} }
/**
* Callback for finished EventSCraper async task
*
* @param event Contains event information if scraping successful
* @param error resId for error message
*/
void scrapeEventResultCallback(FbEvent event, int error) { void scrapeEventResultCallback(FbEvent event, int error) {
if (event != null) { if (event != null) {
@ -115,20 +149,10 @@ public class FbScraper {
} }
/** /**
* cancel vestigial async tasks * start a page scraper and add to list of tasks
*
* @param page_url
*/ */
void killAllTasks() {
try {
for (AsyncTask task : tasks) {
task.cancel(true);
task = null;
}
} catch (Exception e) {
e.printStackTrace();
}
}
void scrapePage(String page_url) { void scrapePage(String page_url) {
FbPageScraper scraper = new FbPageScraper(this, page_url); FbPageScraper scraper = new FbPageScraper(this, page_url);
@ -136,6 +160,12 @@ public class FbScraper {
scraper.execute(); scraper.execute();
} }
/**
* Callback for page scraper async task
*
* @param event_urls List of event urls scraped from the event
* @param error resId of error message if task list is empty
*/
protected void scrapePageResultCallback(List<String> event_urls, int error) { protected void scrapePageResultCallback(List<String> event_urls, int error) {
if (event_urls.size() > 0) { if (event_urls.size() > 0) {
@ -153,8 +183,12 @@ public class FbScraper {
} }
} }
/**
* Start scraping input url
*/
void run() { void run() {
// check if input url is an event
try { try {
String event_url = getEventUrl(input_url); String event_url = getEventUrl(input_url);
url_type = url_type_enum.EVENT; url_type = url_type_enum.EVENT;
@ -165,7 +199,7 @@ public class FbScraper {
} catch (URISyntaxException | MalformedURLException e) { } catch (URISyntaxException | MalformedURLException e) {
url_type = url_type_enum.INVALID; url_type = url_type_enum.INVALID;
} }
// check if input url is a page
try { try {
String page_url = getPageUrl(input_url); String page_url = getPageUrl(input_url);
url_type = url_type_enum.PAGE; url_type = url_type_enum.PAGE;
@ -177,6 +211,6 @@ public class FbScraper {
} }
} }
// enum for storing url type in this class
enum url_type_enum {EVENT, PAGE, INVALID} enum url_type_enum {EVENT, PAGE, INVALID}
} }

View File

@ -1,11 +1,10 @@
package com.akdev.nofbeventscraper; package com.akdev.nofbeventscraper;
import androidx.appcompat.app.AppCompatActivity;
import android.content.Intent; import android.content.Intent;
import android.net.Uri;
import android.os.Bundle; import android.os.Bundle;
import androidx.appcompat.app.AppCompatActivity;
public class IntentReceiver extends AppCompatActivity { public class IntentReceiver extends AppCompatActivity {
@Override @Override

View File

@ -5,7 +5,6 @@ import android.content.ClipboardManager;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.content.SharedPreferences; import android.content.SharedPreferences;
import android.net.Uri;
import android.os.Bundle; import android.os.Bundle;
import android.view.KeyEvent; import android.view.KeyEvent;
import android.view.Menu; import android.view.Menu;
@ -65,17 +64,24 @@ public class MainActivity extends AppCompatActivity {
return list; return list;
} }
/** /*
* Callback for Restoring data * On resume from other activities, e.g. settings
*/ */
@Override @Override
public void onResume() { public void onResume() {
super.onResume(); super.onResume();
/*
* Clear events after saved events deleted from settings
*/
if (getSavedEvents().isEmpty()) {
events.clear(); events.clear();
events.addAll(getSavedEvents());
adapter.notifyDataSetChanged(); adapter.notifyDataSetChanged();
}
/*
* Intent from IntentReceiver - read only once
*/
Intent intent = getIntent(); Intent intent = getIntent();
String data = intent.getStringExtra("InputLink"); String data = intent.getStringExtra("InputLink");
@ -209,7 +215,7 @@ public class MainActivity extends AppCompatActivity {
} }
/** /**
* launch the FbScraper asynchronous task with the current text in the input text field. * launch the FbScraper with the current text in the input text field.
*/ */
public void startScraping() { public void startScraping() {
@ -222,6 +228,12 @@ public class MainActivity extends AppCompatActivity {
scraper.run(); scraper.run();
} }
/**
* manage Helper text on uri_input
*
* @param str What should be displayed
* @param error True if should be displayed as error
*/
public void input_helper(String str, boolean error) { public void input_helper(String str, boolean error) {
if (str == null) { if (str == null) {
@ -255,14 +267,21 @@ public class MainActivity extends AppCompatActivity {
// 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.
getMenuInflater().inflate(R.menu.menu_main, menu); getMenuInflater().inflate(R.menu.menu_main, menu);
/*
* Display icons, restricted API, maybe find other solution?
*/
if (menu instanceof MenuBuilder) { if (menu instanceof MenuBuilder) {
MenuBuilder m = (MenuBuilder) menu; MenuBuilder m = (MenuBuilder) menu;
//noinspection RestrictedApi
m.setOptionalIconsVisible(true); m.setOptionalIconsVisible(true);
} }
return true; return true;
} }
/**
* Dispatch menu item to new activity
* @param item
* @return
*/
@Override @Override
public boolean onOptionsItemSelected(MenuItem item) { public boolean onOptionsItemSelected(MenuItem item) {

View File

@ -1,20 +1,15 @@
package com.akdev.nofbeventscraper; package com.akdev.nofbeventscraper;
import android.content.SharedPreferences; import android.content.SharedPreferences;
import android.graphics.Color;
import android.os.Bundle; import android.os.Bundle;
import android.view.View; import android.view.View;
import android.widget.TextView;
import android.widget.Toast;
import androidx.appcompat.app.ActionBar; import androidx.appcompat.app.ActionBar;
import androidx.appcompat.app.AppCompatActivity; import androidx.appcompat.app.AppCompatActivity;
import androidx.preference.Preference; import androidx.preference.Preference;
import androidx.preference.PreferenceFragmentCompat; import androidx.preference.PreferenceFragmentCompat;
import androidx.preference.PreferenceManager;
import com.google.android.material.snackbar.Snackbar; import com.google.android.material.snackbar.Snackbar;
import com.google.gson.Gson;
public class SettingsActivity extends AppCompatActivity { public class SettingsActivity extends AppCompatActivity {
@ -37,6 +32,9 @@ public class SettingsActivity extends AppCompatActivity {
public void onCreatePreferences(Bundle savedInstanceState, String rootKey) { public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
setPreferencesFromResource(R.xml.root_preferences, rootKey); setPreferencesFromResource(R.xml.root_preferences, rootKey);
/*
* reset events click action: delete saved events and display snackbar
*/
Preference button = findPreference("event_reset"); Preference button = findPreference("event_reset");
if (button != null) { if (button != null) {
button.setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() { button.setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() {