diff --git a/app/src/main/java/com/akdev/nofbeventscraper/EventAdapter.java b/app/src/main/java/com/akdev/nofbeventscraper/EventAdapter.java index a8f25b5..3fc7b89 100644 --- a/app/src/main/java/com/akdev/nofbeventscraper/EventAdapter.java +++ b/app/src/main/java/com/akdev/nofbeventscraper/EventAdapter.java @@ -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; diff --git a/app/src/main/java/com/akdev/nofbeventscraper/FbEventScraper.java b/app/src/main/java/com/akdev/nofbeventscraper/FbEventScraper.java index 9be8b37..3337c26 100644 --- a/app/src/main/java/com/akdev/nofbeventscraper/FbEventScraper.java +++ b/app/src/main/java/com/akdev/nofbeventscraper/FbEventScraper.java @@ -163,6 +163,7 @@ public class FbEventScraper extends AsyncTask { 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 { 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 { } } 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 { } } - - - this.event = new FbEvent(url, name, start_date, end_date, description, location, image_url); } catch (IOException e) { diff --git a/app/src/main/java/com/akdev/nofbeventscraper/FbPageScraper.java b/app/src/main/java/com/akdev/nofbeventscraper/FbPageScraper.java index 2cfcd9a..90d8269 100644 --- a/app/src/main/java/com/akdev/nofbeventscraper/FbPageScraper.java +++ b/app/src/main/java/com/akdev/nofbeventscraper/FbPageScraper.java @@ -22,7 +22,7 @@ public class FbPageScraper extends AsyncTask { private FbScraper scraper; private int error; private String url; - private List event_links = new ArrayList(); + private List event_links = new ArrayList<>(); /** * Constructor with reference to scraper to return results. @@ -58,6 +58,9 @@ public class FbPageScraper extends AsyncTask { 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 event_links_href = document @@ -68,13 +71,16 @@ public class FbPageScraper extends AsyncTask { 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") diff --git a/app/src/main/java/com/akdev/nofbeventscraper/FbScraper.java b/app/src/main/java/com/akdev/nofbeventscraper/FbScraper.java index 7b46c49..7d098d2 100644 --- a/app/src/main/java/com/akdev/nofbeventscraper/FbScraper.java +++ b/app/src/main/java/com/akdev/nofbeventscraper/FbScraper.java @@ -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 events; protected List tasks; + protected WeakReference main; // no context leak with WeakReference url_type_enum url_type = url_type_enum.EVENT; private String input_url; - protected WeakReference 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 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 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} } \ No newline at end of file diff --git a/app/src/main/java/com/akdev/nofbeventscraper/IntentReceiver.java b/app/src/main/java/com/akdev/nofbeventscraper/IntentReceiver.java index 3bbc507..3623f64 100644 --- a/app/src/main/java/com/akdev/nofbeventscraper/IntentReceiver.java +++ b/app/src/main/java/com/akdev/nofbeventscraper/IntentReceiver.java @@ -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 diff --git a/app/src/main/java/com/akdev/nofbeventscraper/MainActivity.java b/app/src/main/java/com/akdev/nofbeventscraper/MainActivity.java index 1e58984..e5e40a2 100644 --- a/app/src/main/java/com/akdev/nofbeventscraper/MainActivity.java +++ b/app/src/main/java/com/akdev/nofbeventscraper/MainActivity.java @@ -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) { diff --git a/app/src/main/java/com/akdev/nofbeventscraper/SettingsActivity.java b/app/src/main/java/com/akdev/nofbeventscraper/SettingsActivity.java index ef891a0..6d1ecc8 100644 --- a/app/src/main/java/com/akdev/nofbeventscraper/SettingsActivity.java +++ b/app/src/main/java/com/akdev/nofbeventscraper/SettingsActivity.java @@ -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; }