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
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("")) {
holder.text_view_event_location.setText(event.location);
} else {
@ -86,7 +90,6 @@ public class EventAdapter extends
}
if (!event.description.equals("")) {
holder.text_view_event_description.setText(event.description);
} else {
@ -120,13 +123,14 @@ public class EventAdapter extends
};
holder.image_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
*/
holder.button_add_to_calendar.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
// calendar event intent expects epoch time format
Long start_epoch = dateTimeToEpoch(event.start_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() {
@ -198,7 +202,6 @@ public class EventAdapter extends
});
}
};
holder.image_view_event_image.setOnClickListener(listener);
@ -212,6 +215,9 @@ public class EventAdapter extends
return events.size();
}
/**
* access item view elements via holder class
*/
public static class ViewHolder extends RecyclerView.ViewHolder {
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);
// get all fields from json event information
name = readFromJson(reader, "name");
start_date = parseToDate(readFromJson(reader, "startDate"));
end_date = parseToDate(readFromJson(reader, "endDate"));
@ -170,6 +171,7 @@ public class FbEventScraper extends AsyncTask<Void, Void, Void> {
location = fixLocation(readFromJson(reader, "location"));
image_url = readFromJson(reader, "image");
// try to find a high-res image
try {
image_url = document.select("div[id=event_header_primary]")
.select("img").first().attr("src");
@ -177,6 +179,7 @@ public class FbEventScraper extends AsyncTask<Void, Void, Void> {
}
} catch (JSONException | NullPointerException e) {
// json event information mot found. get at least title and image
name = document.title();
description = scraper.main.get().getString(R.string.error_scraping);
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);
} catch (IOException e) {

View File

@ -22,7 +22,7 @@ public class FbPageScraper extends AsyncTask<Void, Void, Void> {
private FbScraper scraper;
private int error;
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.
@ -58,6 +58,9 @@ public class FbPageScraper extends AsyncTask<Void, Void, Void> {
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]*)?";
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);
}
/*
* check if more events should scraped
*/
SharedPreferences shared_prefs = PreferenceManager
.getDefaultSharedPreferences(scraper.main.get());
int max = shared_prefs.getInt("page_event_max", 5);
if (event_links.size() < max) {
// find "next page
try {
String next_url = document
.getElementsByAttributeValueMatching("href", "has_more=1")

View File

@ -14,15 +14,12 @@ import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import static com.akdev.nofbeventscraper.FbEvent.createEventList;
public class FbScraper {
protected List<FbEvent> events;
protected List<AsyncTask> tasks;
protected WeakReference<MainActivity> main; // no context leak with WeakReference
url_type_enum url_type = url_type_enum.EVENT;
private String input_url;
protected WeakReference<MainActivity> main; // no context leak with WeakReference
/**
* Constructor with WeakReference to the main activity, to add events.
@ -33,10 +30,18 @@ public class FbScraper {
FbScraper(WeakReference<MainActivity> main, String input_url) {
this.main = main;
this.input_url = input_url;
this.events = createEventList();
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 {
// check for url format
@ -48,10 +53,11 @@ public class FbScraper {
Matcher matcher = pattern.matcher(url);
if (matcher.find()) {
//only mbasic does have event ids displayed in HTML
String url_prefix = "https://mbasic.facebook.com/";
String url_suffix = "?v=events";
// create URL
return url_prefix + matcher.group(3) + url_suffix;
} 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
* @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) {
FbEventScraper scraper = new FbEventScraper(this, event_url);
tasks.add(scraper);
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) {
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) {
FbPageScraper scraper = new FbPageScraper(this, page_url);
@ -136,6 +160,12 @@ public class FbScraper {
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) {
if (event_urls.size() > 0) {
@ -153,8 +183,12 @@ public class FbScraper {
}
}
/**
* Start scraping input url
*/
void run() {
// check if input url is an event
try {
String event_url = getEventUrl(input_url);
url_type = url_type_enum.EVENT;
@ -165,7 +199,7 @@ public class FbScraper {
} catch (URISyntaxException | MalformedURLException e) {
url_type = url_type_enum.INVALID;
}
// check if input url is a page
try {
String page_url = getPageUrl(input_url);
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}
}

View File

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

View File

@ -5,7 +5,6 @@ import android.content.ClipboardManager;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.net.Uri;
import android.os.Bundle;
import android.view.KeyEvent;
import android.view.Menu;
@ -65,17 +64,24 @@ public class MainActivity extends AppCompatActivity {
return list;
}
/**
* Callback for Restoring data
/*
* On resume from other activities, e.g. settings
*/
@Override
public void onResume() {
super.onResume();
events.clear();
events.addAll(getSavedEvents());
adapter.notifyDataSetChanged();
/*
* Clear events after saved events deleted from settings
*/
if (getSavedEvents().isEmpty()) {
events.clear();
adapter.notifyDataSetChanged();
}
/*
* Intent from IntentReceiver - read only once
*/
Intent intent = getIntent();
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() {
@ -222,6 +228,12 @@ public class MainActivity extends AppCompatActivity {
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) {
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.
getMenuInflater().inflate(R.menu.menu_main, menu);
/*
* Display icons, restricted API, maybe find other solution?
*/
if (menu instanceof MenuBuilder) {
MenuBuilder m = (MenuBuilder) menu;
//noinspection RestrictedApi
m.setOptionalIconsVisible(true);
}
return true;
}
/**
* Dispatch menu item to new activity
* @param item
* @return
*/
@Override
public boolean onOptionsItemSelected(MenuItem item) {

View File

@ -1,20 +1,15 @@
package com.akdev.nofbeventscraper;
import android.content.SharedPreferences;
import android.graphics.Color;
import android.os.Bundle;
import android.view.View;
import android.widget.TextView;
import android.widget.Toast;
import androidx.appcompat.app.ActionBar;
import androidx.appcompat.app.AppCompatActivity;
import androidx.preference.Preference;
import androidx.preference.PreferenceFragmentCompat;
import androidx.preference.PreferenceManager;
import com.google.android.material.snackbar.Snackbar;
import com.google.gson.Gson;
public class SettingsActivity extends AppCompatActivity {
@ -37,6 +32,9 @@ public class SettingsActivity extends AppCompatActivity {
public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
setPreferencesFromResource(R.xml.root_preferences, rootKey);
/*
* reset events click action: delete saved events and display snackbar
*/
Preference button = findPreference("event_reset");
if (button != null) {
button.setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() {
@ -52,11 +50,11 @@ public class SettingsActivity extends AppCompatActivity {
getString(R.string.preferences_event_snackbar), Snackbar.LENGTH_SHORT)
.setAction(R.string.undo, new View.OnClickListener() {
@Override
public void onClick(View v) {
prefs.edit().putString("events", undo).apply();
}
}).show();
@Override
public void onClick(View v) {
prefs.edit().putString("events", undo).apply();
}
}).show();
return true;
}