fix event info hiding after activity restore (closes #23), add comments
This commit is contained in:
parent
ce790763fd
commit
9e81e3d74a
|
@ -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;
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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")
|
||||||
|
|
|
@ -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}
|
||||||
}
|
}
|
|
@ -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
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
||||||
|
|
|
@ -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() {
|
||||||
|
|
Loading…
Reference in New Issue