From 16d390094eb6b80ffa6b7e947531feadfdcf2df3 Mon Sep 17 00:00:00 2001 From: akaessens <24660231+akaessens@users.noreply.github.com> Date: Fri, 28 Aug 2020 14:31:45 +0200 Subject: [PATCH] much refactoring: -move event formatting logic to event class -disable editing of event output, it's available in the calendar app -replace string datetimes with ZonedDateZime -move uri checking logic to scraper -update exception handling and error messages -reformatting and renaming -fix messy xml layouts -update tests -add comments --- app/build.gradle | 4 +- .../MainActivityUnitTest.java | 110 ----- .../nofbeventscraper/ScraperUnitTest.java | 41 +- .../com/akdev/nofbeventscraper/FbEvent.java | 33 +- .../com/akdev/nofbeventscraper/FbScraper.java | 152 ++++--- .../akdev/nofbeventscraper/MainActivity.java | 410 ++++++++---------- app/src/main/res/layout/activity_main.xml | 5 +- app/src/main/res/layout/content_main.xml | 240 +++++----- 8 files changed, 427 insertions(+), 568 deletions(-) delete mode 100644 app/src/androidTest/java/com/akdev/nofbeventscraper/MainActivityUnitTest.java diff --git a/app/build.gradle b/app/build.gradle index 19e8945..57f4764 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -40,6 +40,6 @@ dependencies { implementation 'com.squareup.picasso:picasso:2.71828' testImplementation 'junit:junit:4.12' - androidTestImplementation 'androidx.test.ext:junit:1.1.1' - androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0' + androidTestImplementation 'androidx.test.ext:junit:1.1.2' + androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0' } diff --git a/app/src/androidTest/java/com/akdev/nofbeventscraper/MainActivityUnitTest.java b/app/src/androidTest/java/com/akdev/nofbeventscraper/MainActivityUnitTest.java deleted file mode 100644 index 78bae73..0000000 --- a/app/src/androidTest/java/com/akdev/nofbeventscraper/MainActivityUnitTest.java +++ /dev/null @@ -1,110 +0,0 @@ -package com.akdev.nofbeventscraper; - -import android.app.Activity; -import android.app.Instrumentation; -import android.content.Context; -import android.content.Intent; - -import androidx.test.ext.junit.runners.AndroidJUnit4; -import androidx.test.platform.app.InstrumentationRegistry; - -import org.junit.Test; -import org.junit.runner.RunWith; - -import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation; -import static org.junit.Assert.assertEquals; - -@RunWith(AndroidJUnit4.class) -public class MainActivityUnitTest { - - @Test - public void TestSubdomainUrl() { - - - Instrumentation mInstrumentation = getInstrumentation(); - // We register our interest in the activity - Instrumentation.ActivityMonitor monitor = mInstrumentation.addMonitor(MainActivity.class.getName(), null, false); - // We launch it - Intent intent = new Intent(Intent.ACTION_MAIN); - intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - intent.setClassName(mInstrumentation.getTargetContext(), MainActivity.class.getName()); - mInstrumentation.startActivitySync(intent); - - MainActivity mainActivity = (MainActivity) getInstrumentation().waitForMonitor(monitor); - - // We register our interest in the next activity from the sequence in this use case - mInstrumentation.removeMonitor(monitor); - - - final String exp = "https://m.facebook.com/events/261145401687844"; - - String url = "https://www.facebook.com/events/261145401687844"; - String act = mainActivity.checkURI(url); - assertEquals(exp, act); - - url = "https://de-de.facebook.com/events/261145401687844"; - act = mainActivity.checkURI(url); - assertEquals(exp, act); - - url = "https://m.facebook.com/events/261145401687844"; - act = mainActivity.checkURI(url); - assertEquals(exp, act); - - url = "https://www.facebook.com/events/261145401687844/?active_tab=discussion"; - act = mainActivity.checkURI(url); - assertEquals(exp, act); - - url = "https://www.facebook.com/events/261145401687844?reflink_something"; - act = mainActivity.checkURI(url); - assertEquals(exp, act); - } - - @Test - public void TestTimeToEpoch() { - - - Instrumentation mInstrumentation = getInstrumentation(); - // We register our interest in the activity - Instrumentation.ActivityMonitor monitor = mInstrumentation.addMonitor(MainActivity.class.getName(), null, false); - // We launch it - Intent intent = new Intent(Intent.ACTION_MAIN); - intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - intent.setClassName(mInstrumentation.getTargetContext(), MainActivity.class.getName()); - mInstrumentation.startActivitySync(intent); - - MainActivity mainActivity = (MainActivity) getInstrumentation().waitForMonitor(monitor); - - // We register our interest in the next activity from the sequence in this use case - mInstrumentation.removeMonitor(monitor); - - - String in = "2020-07-29T12:00:00+00:00"; - - Long exp = new Long(1596024000); - exp = exp* 1000; - Long act = mainActivity.convertTimeToEpoch(in); - assertEquals(exp, act); - - - in = "2020-07-29T12:00:00+02:00"; - exp = new Long(1596016800); - exp = exp* 1000; - act = mainActivity.convertTimeToEpoch(in); - assertEquals(exp, act); - - - in = "1970-01-01T00:00:00+00:00"; - exp = new Long(0); - exp = exp* 1000; - act = mainActivity.convertTimeToEpoch(in); - assertEquals(exp, act); - - in = "1970-01-01T02:00:00+02:00"; - exp = new Long(0); - exp = exp* 1000; - act = mainActivity.convertTimeToEpoch(in); - assertEquals(exp, act); - - } - -} diff --git a/app/src/androidTest/java/com/akdev/nofbeventscraper/ScraperUnitTest.java b/app/src/androidTest/java/com/akdev/nofbeventscraper/ScraperUnitTest.java index 06592db..81ce5ba 100644 --- a/app/src/androidTest/java/com/akdev/nofbeventscraper/ScraperUnitTest.java +++ b/app/src/androidTest/java/com/akdev/nofbeventscraper/ScraperUnitTest.java @@ -5,13 +5,19 @@ import androidx.test.ext.junit.runners.AndroidJUnit4; import org.junit.Test; import org.junit.runner.RunWith; +import java.net.MalformedURLException; +import java.net.URISyntaxException; +import java.time.ZonedDateTime; +import java.time.format.DateTimeFormatter; + import static org.junit.Assert.assertEquals; @RunWith(AndroidJUnit4.class) public class ScraperUnitTest { @Test - public void TestLocation() { + public void testLocation() { + FbScraper scraper = new FbScraper(null, ""); @@ -32,37 +38,50 @@ public class ScraperUnitTest { } @Test - public void TestTimezone() { + public void testTimezone() { FbScraper scraper = new FbScraper(null, ""); - String exp = "2020-10-23T05:00:00+02:00"; + String exp = "2020-10-23T05:00+02:00"; String in = "2020-10-23T05:00:00+0200"; - String act = scraper.fixTimezone(in); + String act = scraper.toZonedDateTime(in).toString(); assertEquals(exp, act); - exp = ""; + exp = null; in = ""; - act = scraper.fixTimezone(in); - assertEquals(exp, act); - + ZonedDateTime act2 = scraper.toZonedDateTime(in); + assertEquals(exp, act2); } @Test - public void TestLinks() { + public void testDescriptionLinks() { FbScraper scraper = new FbScraper(null, ""); String in = "foo @[152580919265:274:MagentaMusik 360] bar"; String exp = "foo MagentaMusik 360 [m.facebook.com/152580919265] bar"; - String act = scraper.fixLinks(in); + String act = scraper.fixDescriptionLinks(in); assertEquals(exp, act); in = "foo @[152580919265:274:MagentaMusik 360] bar @[666666666666:274:NoOfTheBeast]"; exp = "foo MagentaMusik 360 [m.facebook.com/152580919265] bar NoOfTheBeast [m.facebook.com/666666666666]"; - act = scraper.fixLinks(in); + act = scraper.fixDescriptionLinks(in); + assertEquals(exp, act); + } + + @Test + public void testURI() throws MalformedURLException, URISyntaxException { + + FbScraper scraper = new FbScraper(null, ""); + + String in = "https://www.facebook.com/events/1234324522341432?refsomething"; + String exp = "https://m.facebook.com/events/1234324522341432"; + String act = scraper.fixURI(in); assertEquals(exp, act); + in = "https://de-de.facebook.com/events/1234324522341432/?active_tab=discussion"; + act = scraper.fixURI(in); + assertEquals(exp, act); } } diff --git a/app/src/main/java/com/akdev/nofbeventscraper/FbEvent.java b/app/src/main/java/com/akdev/nofbeventscraper/FbEvent.java index 1bbcf48..32fd8a7 100644 --- a/app/src/main/java/com/akdev/nofbeventscraper/FbEvent.java +++ b/app/src/main/java/com/akdev/nofbeventscraper/FbEvent.java @@ -1,14 +1,24 @@ package com.akdev.nofbeventscraper; +import java.time.ZonedDateTime; +import java.time.format.DateTimeFormatter; +import java.time.format.FormatStyle; + public class FbEvent { + + public String url; public String name; - public String start_date; - public String end_date; + public ZonedDateTime start_date; + public ZonedDateTime end_date; public String description; public String location; public String image_url; - public FbEvent (String name, String start_date, String end_date, String description, String location, String image_url) { + public FbEvent() { + + } + + public FbEvent(String name, ZonedDateTime start_date, ZonedDateTime end_date, String description, String location, String image_url) { this.name = name; this.start_date = start_date; this.end_date = end_date; @@ -16,4 +26,21 @@ public class FbEvent { this.location = location; this.image_url = image_url; } + + + static Long dateTimeToEpoch(ZonedDateTime datetime) { + try { + return datetime.toEpochSecond() * 1000; + } catch (Exception e) { + return null; + } + } + + static String dateTimeToString(ZonedDateTime datetime) { + try { + return DateTimeFormatter.ofLocalizedDateTime(FormatStyle.MEDIUM).format(datetime); + } catch (Exception e) { + return ""; + } + } } diff --git a/app/src/main/java/com/akdev/nofbeventscraper/FbScraper.java b/app/src/main/java/com/akdev/nofbeventscraper/FbScraper.java index 1d0a546..da3d0f1 100644 --- a/app/src/main/java/com/akdev/nofbeventscraper/FbScraper.java +++ b/app/src/main/java/com/akdev/nofbeventscraper/FbScraper.java @@ -1,6 +1,5 @@ package com.akdev.nofbeventscraper; - import android.os.AsyncTask; import android.text.Editable; import android.text.SpannableStringBuilder; @@ -11,69 +10,100 @@ import org.jsoup.Jsoup; import org.jsoup.nodes.Document; import java.io.IOException; +import java.lang.ref.WeakReference; +import java.net.MalformedURLException; +import java.net.URISyntaxException; +import java.net.URL; +import java.time.ZonedDateTime; +import java.time.format.DateTimeFormatter; +import java.util.regex.Matcher; +import java.util.regex.Pattern; public class FbScraper extends AsyncTask { - private String url; private String error; - private MainActivity main; + private String input_str; + private WeakReference main; // no context leak with WeakReference private FbEvent event; - FbScraper(MainActivity main, String url) { - this.url = url; + FbScraper(WeakReference main, String str) { this.main = main; + this.input_str = str; + } + + protected String fixURI(String str) throws URISyntaxException, MalformedURLException { + + // check for url format + new URL(str).toURI(); + + Pattern pattern = Pattern.compile("(facebook.com/events/[0-9]*)"); + Matcher matcher = pattern.matcher(str); + + if (matcher.find()) { + // rewrite url to m.facebook and dismiss any query strings or referrals + return "https://m." + matcher.group(1); + } else { + throw new URISyntaxException(str, "Does not contain event."); + } } + protected String fixLocation(String location_json) { - String name = ""; + String location_name = ""; try { JSONObject reader = new JSONObject(location_json); - name = reader.getString("name"); + location_name = reader.getString("name"); JSONObject address = reader.getJSONObject("address"); String type = address.getString("@type"); - if (type.equals("PostalAddress")) - { + if (type.equals("PostalAddress")) { String postal_code = address.getString("postalCode"); String address_locality = address.getString("addressLocality"); - String address_country = address.getString("addressCountry"); String street_address = address.getString("streetAddress"); + // included in locality + //String address_country = address.getString("addressCountry"); - return name + ", " + street_address + ", " + postal_code + " " + address_locality; - } - else - { - return name; - } + return location_name + ", " + + street_address + ", " + + postal_code + " " + + address_locality; + } else { + return location_name; + } } catch (JSONException e) { e.printStackTrace(); - return name; + return location_name; } } - protected String fixTimezone(String time_in) { + protected ZonedDateTime toZonedDateTime(String time_in) { try { - + // time in is missing a : in the timezone offset Editable editable = new SpannableStringBuilder(time_in); + String time_str = editable.insert(22, ":").toString(); - return editable.insert(22, ":").toString(); + // parse e.g. 2011-12-03T10:15:30+01:00 + return ZonedDateTime.parse(time_str, DateTimeFormatter.ISO_OFFSET_DATE_TIME); } catch (Exception e) { e.printStackTrace(); - return ""; + return null; } } - protected String fixLinks(String description_in) { + protected String fixDescriptionLinks(String description_in) { try { - // @[152580919265:274:MagentaMusik 360] -> m.facebook.com/152580919265 + /* @[152580919265:274:SiteDescription] + * to + * SiteDescription [m.facebook.com/152580919265] */ + return description_in.replaceAll("@\\[([0-9]{10,}):[0-9]{3}:([^]]*)]", "$2 [m.facebook.com/$1]"); @@ -86,60 +116,45 @@ public class FbScraper extends AsyncTask { private String readFromJson(JSONObject reader, String field) { try { return reader.getString(field); - } - catch (Exception e) { + } catch (Exception e) { e.printStackTrace(); return ""; } } + @Override protected Void doInBackground(Void... voids) { - Document document = null; - try { - document = Jsoup.connect(url).userAgent("Mozilla").get(); + String url = fixURI(input_str); + // useragent needed with Jsoup > 1.12 + Document document = Jsoup.connect(url).userAgent("Mozilla").get(); + String json = document + .select("script[type = application/ld+json]") + .first().data(); - try { - String json = document.select("script[type = application/ld+json]").first().data(); + JSONObject reader = new JSONObject(json); - JSONObject reader = new JSONObject(json); + event = new FbEvent(); + event.url = url; + event.name = readFromJson(reader, "name"); + event.start_date = toZonedDateTime(readFromJson(reader, "startDate")); + event.end_date = toZonedDateTime(readFromJson(reader, "endDate")); + event.description = fixDescriptionLinks(readFromJson(reader, "description")); + event.location = fixLocation(readFromJson(reader, "location")); + event.image_url = readFromJson(reader, "image"); - String event_name = readFromJson(reader, "name"); - String event_start = fixTimezone(readFromJson(reader, "startDate")); - String event_end = fixTimezone(readFromJson(reader, "endDate")); - - String event_description = fixLinks(readFromJson(reader, "description")); - String location = fixLocation(readFromJson(reader, "location")); - - String image_url = ""; - - try { - image_url = readFromJson(reader, "image"); // get from json - - // get from event header - image_url = document.getElementsByClass("scaledImageFitWidth").first().attr("src"); - } catch (Exception e) { - e.printStackTrace(); - this.error = "Error: no image found"; - } - - if (event_name == null) { - this.event = null; - throw new Exception(); - } else { - this.event = new FbEvent(event_name, event_start, event_end, event_description, location, image_url); - //this.event = new FbEvent("", "", "", "", "", ""); - } - - } catch (Exception e) { - e.printStackTrace(); - this.error = "Error: Scraping event data failed"; - } - } catch (Exception e) { + } catch (URISyntaxException | MalformedURLException e) { e.printStackTrace(); - this.error = "Error: URL not available"; + this.error = "Error: URL invalid."; + } catch (JSONException e) { + e.printStackTrace(); + this.error = "Error: Scraping event data failed"; + } catch (IOException e) { + e.printStackTrace(); + this.error = "Error: Unable to connect."; } + return null; } @@ -152,11 +167,10 @@ public class FbScraper extends AsyncTask { super.onPostExecute(aVoid); if (this.event != null) { - this.main.update(event); - } - else { - main.error(error); - this.main.clear(false); + main.get().update(event); + } else { + main.get().error(error); + main.get().clear(false); } } } diff --git a/app/src/main/java/com/akdev/nofbeventscraper/MainActivity.java b/app/src/main/java/com/akdev/nofbeventscraper/MainActivity.java index 2b0452f..b30d71a 100644 --- a/app/src/main/java/com/akdev/nofbeventscraper/MainActivity.java +++ b/app/src/main/java/com/akdev/nofbeventscraper/MainActivity.java @@ -5,12 +5,6 @@ import android.content.Context; import android.content.Intent; import android.net.Uri; import android.os.Bundle; - -import com.google.android.material.appbar.AppBarLayout; -import com.google.android.material.appbar.CollapsingToolbarLayout; -import com.google.android.material.textfield.TextInputEditText; -import androidx.appcompat.app.AppCompatActivity; -import androidx.appcompat.widget.Toolbar; import android.provider.CalendarContract; import android.view.KeyEvent; import android.view.Menu; @@ -19,32 +13,39 @@ import android.view.View; import android.widget.Button; import android.widget.ImageView; +import androidx.appcompat.app.AppCompatActivity; +import androidx.appcompat.widget.Toolbar; + +import com.google.android.material.appbar.AppBarLayout; +import com.google.android.material.appbar.CollapsingToolbarLayout; +import com.google.android.material.textfield.TextInputEditText; import com.google.android.material.textfield.TextInputLayout; import com.squareup.picasso.Picasso; -import java.net.URL; -import java.time.ZonedDateTime; -import java.time.format.DateTimeFormatter; -import java.util.regex.Matcher; -import java.util.regex.Pattern; +import java.lang.ref.WeakReference; +import static com.akdev.nofbeventscraper.FbEvent.dateTimeToEpoch; public class MainActivity extends AppCompatActivity { - private Button paste_button; - private Button ok_button; + protected Button ok_button; + protected Button paste_button; - private TextInputEditText field_uri_input; - private TextInputEditText field_event_name; - private TextInputEditText field_event_start; - private TextInputEditText field_event_end; - private TextInputEditText field_event_location; - private TextInputEditText field_event_description; - private ImageView toolbar_image_view; - private CollapsingToolbarLayout toolbar_layout; - private TextInputLayout input_layout; - private TextInputLayout location_layout; - private FbScraper scraper; + protected TextInputEditText edit_text_uri_input; + protected TextInputEditText edit_text_event_name; + protected TextInputEditText edit_text_event_start; + protected TextInputEditText edit_text_event_end; + protected TextInputEditText edit_text_event_location; + protected TextInputEditText edit_text_event_description; + + protected TextInputLayout layout_uri_input; + protected TextInputLayout layout_event_location; + + protected ImageView image_view_toolbar; + protected CollapsingToolbarLayout layout_toolbar; + + protected FbScraper scraper; + protected FbEvent event; @Override protected void onCreate(Bundle savedInstanceState) { @@ -56,43 +57,52 @@ public class MainActivity extends AppCompatActivity { ok_button = (Button) findViewById(R.id.ok_button); paste_button = (Button) findViewById(R.id.paste_button); - field_uri_input = (TextInputEditText) findViewById(R.id.field_uri_input); - input_layout = (TextInputLayout) findViewById(R.id.textInputLayout); - location_layout = (TextInputLayout) findViewById(R.id.location_layout); - field_event_name = (TextInputEditText) findViewById(R.id.field_event_name); - field_event_start = (TextInputEditText) findViewById(R.id.field_event_start); - field_event_end = (TextInputEditText) findViewById(R.id.field_event_end); - field_event_location = (TextInputEditText) findViewById(R.id.field_event_location); - field_event_description = (TextInputEditText) findViewById(R.id.field_event_description); - toolbar_image_view = (ImageView) findViewById(R.id.image_view); - toolbar_layout = (CollapsingToolbarLayout) findViewById(R.id.toolbar_layout); + edit_text_uri_input = (TextInputEditText) findViewById(R.id.edit_text_uri_input); + edit_text_event_name = (TextInputEditText) findViewById(R.id.edit_text_event_name); + edit_text_event_start = (TextInputEditText) findViewById(R.id.edit_text_event_start); + edit_text_event_end = (TextInputEditText) findViewById(R.id.edit_text_event_end); + edit_text_event_location = (TextInputEditText) findViewById(R.id.edit_text_event_location); + edit_text_event_description = (TextInputEditText) findViewById(R.id.edit_text_event_description); + + layout_uri_input = (TextInputLayout) findViewById(R.id.layout_uri_input); + layout_event_location = (TextInputLayout) findViewById(R.id.layout_event_location); + layout_toolbar = (CollapsingToolbarLayout) findViewById(R.id.layout_toolbar); + image_view_toolbar = (ImageView) findViewById(R.id.image_view); + /* + * Default view settings + */ ok_button.setEnabled(false); - location_layout.setEndIconVisible(false); - - toolbar_image_view.setImageResource(R.drawable.ic_banner_foreground); + layout_event_location.setEndIconVisible(false); + image_view_toolbar.setImageResource(R.drawable.ic_banner_foreground); + /* + * Display title only when toolbar is collapsed + */ AppBarLayout app_bar_layout = (AppBarLayout) findViewById(R.id.app_bar); app_bar_layout.addOnOffsetChangedListener(new AppBarLayout.OnOffsetChangedListener() { - boolean isShow = true; - int scrollRange = -1; + boolean show = true; + int scroll_range = -1; @Override - public void onOffsetChanged(AppBarLayout appBarLayout, int verticalOffset) { - if (scrollRange == -1) { - scrollRange = appBarLayout.getTotalScrollRange(); + public void onOffsetChanged(AppBarLayout app_bar_layout, int vertical_offset) { + if (scroll_range == -1) { + scroll_range = app_bar_layout.getTotalScrollRange(); } - if (scrollRange + verticalOffset == 0) { - toolbar_layout.setTitle(getString(R.string.app_name)); - isShow = true; - } else if(isShow) { - toolbar_layout.setTitle(" "); - isShow = false; + if (scroll_range + vertical_offset == 0) { + layout_toolbar.setTitle(getString(R.string.app_name)); + show = true; + } else if (show) { + layout_toolbar.setTitle(" "); + show = false; } } }); + /* + * Paste button: get last entry from clipboard + */ paste_button.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { @@ -102,9 +112,8 @@ public class MainActivity extends AppCompatActivity { String str = clipboard.getPrimaryClip().getItemAt(0).getText().toString(); clear(true); - field_uri_input.setText(str); - } - catch (NullPointerException e) { + edit_text_uri_input.setText(str); + } catch (NullPointerException e) { e.printStackTrace(); error("Error: Clipboard empty"); } @@ -112,71 +121,65 @@ public class MainActivity extends AppCompatActivity { } }); - - input_layout.setEndIconOnClickListener(new View.OnClickListener() { + /* + * Clear button: delete all text in all fields + */ + View.OnClickListener listener = new View.OnClickListener() { @Override public void onClick(View view) { clear(true); } - }); - input_layout.setErrorIconOnClickListener(new View.OnClickListener() { + }; + layout_uri_input.setEndIconOnClickListener(listener); + layout_uri_input.setErrorIconOnClickListener(listener); + + /* + * Maps button: launch maps intent + */ + layout_event_location.setEndIconOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { - clear(true); - } - }); + String map_search = "geo:0,0?q=" + edit_text_event_location.getText(); - - location_layout.setEndIconOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View view) { - String map_search = "geo:0,0?q=" + field_event_location.getText(); - - Uri gmmIntentUri = Uri.parse(map_search); - Intent mapIntent = new Intent(Intent.ACTION_VIEW, gmmIntentUri); - //mapIntent.setPackage("com.google.android.apps.maps"); - if (mapIntent.resolveActivity(getPackageManager()) != null) { - startActivity(mapIntent); + Uri intent_uri = Uri.parse(map_search); + Intent map_intent = new Intent(Intent.ACTION_VIEW, intent_uri); + if (map_intent.resolveActivity(getPackageManager()) != null) { + startActivity(map_intent); } - } }); - + /* + * Add to calendar button: launch calendar application + */ ok_button.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { - try { - Long start_epoch = convertTimeToEpoch(field_event_start.getText().toString()); - Long end_epoch = convertTimeToEpoch(field_event_end.getText().toString()); - String name = parseField(field_event_name); + Long start_epoch = dateTimeToEpoch(event.start_date); + Long end_epoch = dateTimeToEpoch(event.end_date); - String location = parseField(field_event_location); - String description = parseField(field_event_description); - String uri = parseField(field_uri_input); - - Intent intent = new Intent(Intent.ACTION_EDIT); - intent.setType("vnd.android.cursor.item/event"); - intent.putExtra(CalendarContract.Events.TITLE, name); - intent.putExtra(CalendarContract.EXTRA_EVENT_BEGIN_TIME, start_epoch); - intent.putExtra(CalendarContract.EXTRA_EVENT_END_TIME, end_epoch); - intent.putExtra(CalendarContract.Events.EVENT_LOCATION, location); - intent.putExtra(CalendarContract.Events.DESCRIPTION, uri + "\n\n" + description); - startActivity(intent); - } - catch (Exception e ) - { - e.printStackTrace(); - } + Intent intent = new Intent(Intent.ACTION_EDIT); + intent.setType("vnd.android.cursor.item/event"); + intent.putExtra(CalendarContract.Events.TITLE, event.name); + intent.putExtra(CalendarContract.EXTRA_EVENT_BEGIN_TIME, start_epoch); + intent.putExtra(CalendarContract.EXTRA_EVENT_END_TIME, end_epoch); + intent.putExtra(CalendarContract.Events.EVENT_LOCATION, event.location); + // prepend url in description + String desc = event.url + "\n\n" + event.description; + intent.putExtra(CalendarContract.Events.DESCRIPTION, desc); + startActivity(intent); } }); - field_uri_input.setOnKeyListener(new View.OnKeyListener() { - public boolean onKey(View view, int keyCode, KeyEvent keyevent) { - //If the keyevent is a key-down event on the "enter" button - if ((keyevent.getAction() == KeyEvent.ACTION_DOWN) && (keyCode == KeyEvent.KEYCODE_ENTER)) { + /* + * Enter button in uri input: start scraping + */ + edit_text_uri_input.setOnKeyListener(new View.OnKeyListener() { + public boolean onKey(View view, int keycode, KeyEvent keyevent) { + //If the key event is a key-down event on the "enter" button + if ((keyevent.getAction() == KeyEvent.ACTION_DOWN) && (keycode == KeyEvent.KEYCODE_ENTER)) { startScraping(); return true; } @@ -184,175 +187,122 @@ public class MainActivity extends AppCompatActivity { } }); - //get data from deep link + + /* + * Get data from intent: if launched by other application + * via "share to" or "open with" + */ Intent intent = getIntent(); Uri data = intent.getData(); String shared_text = intent.getStringExtra(Intent.EXTRA_TEXT); if (data != null) { // opening external fb link - field_uri_input.setText(data.toString()); + edit_text_uri_input.setText(data.toString()); startScraping(); - } - else if (shared_text != null) { + } else if (shared_text != null) { //share to nofb - field_uri_input.setText(shared_text); + edit_text_uri_input.setText(shared_text); startScraping(); } } - private String parseField(TextInputEditText field) { - try { - return field.getText().toString(); - } - catch (Exception e) { - return null; - } - } - - - Long convertTimeToEpoch(String time_str) { - try { - ZonedDateTime datetime = ZonedDateTime.parse(time_str, DateTimeFormatter.ISO_DATE_TIME); - - return datetime.toEpochSecond() * 1000; - } catch (Exception e) - { - e.printStackTrace(); - } - return null; - } - - String checkURI(String str) - { - try { - - // check for a valid uri - new URL(str).toURI(); - - Pattern pattern = Pattern.compile("(facebook.com/events/[0-9]*)"); - Matcher matcher = pattern.matcher(str); - - if (matcher.find()) - { - return "https://m." + matcher.group(1); - } - else - { - error("Error: Invalid URL"); - clear(false); - return ""; - } - - } - catch (Exception e) { - e.printStackTrace(); - error("Error: Invalid URL"); - clear(false); - return ""; - } - } public void startScraping() { error(null); try { - String str = checkURI(field_uri_input.getText().toString()); + String url = edit_text_uri_input.getText().toString(); + scraper = new FbScraper(new WeakReference<>(this), url); + scraper.execute(); - - if (!str.equals("")) - { - field_uri_input.setText(str); - scraper = new FbScraper(this, field_uri_input.getText().toString()); - scraper.execute(); - } - - } - catch (Exception e) { + } catch (Exception e) { e.printStackTrace(); error("Error: Invalid URL"); } - } + public void error(String str) { - //Toast.makeText(this, str, Toast.LENGTH_SHORT).show(); - input_layout.setError(str); - } - public void clear(boolean clearUri) { - if (clearUri) { - field_uri_input.setText(""); - } - field_event_name.setText(""); - field_event_name.setError(null); - field_event_start.setText(""); - field_event_start.setError(null); - field_event_end.setText(""); - field_event_end.setError(null); - field_event_location.setText(""); - field_event_location.setError(null); - field_event_description.setText(""); - field_event_description.setError(null); - toolbar_image_view.setImageDrawable(null); - - if (scraper!=null) - { - scraper.cancel(true); - scraper = null; - } - ok_button.setEnabled(false); - location_layout.setEndIconVisible(false); - toolbar_image_view.setImageResource(R.drawable.ic_banner_foreground); + layout_uri_input.setError(str); } - public void update(FbEvent event) { - field_event_name.setText(event.name); - input_layout.setError(null); + public void clear(boolean clear_uri) { - if (event.name.equals("")) - { - field_event_name.setError("no event name detected"); - } - field_event_start.setText(event.start_date); - - if (event.start_date.equals("")) - { - field_event_start.setError("no event start date detected"); - } - field_event_end.setText(event.end_date); - - if (event.end_date.equals("")) - { - field_event_end.setError("no event end date detected"); - } - - field_event_location.setText(event.location); - - if (event.location.equals("")) - { - field_event_location.setError("no event location detected"); - } - else - { - location_layout.setEndIconVisible(true); - field_event_location.setError(null); - } - field_event_description.setText(event.description); - - if (event.description.equals("")) - { - field_event_description.setError("no event description detected"); + if (clear_uri) { + edit_text_uri_input.setText(""); + layout_uri_input.setError(null); } + edit_text_event_name.setText(""); + edit_text_event_start.setText(""); + edit_text_event_end.setText(""); + edit_text_event_location.setText(""); + edit_text_event_description.setText(""); + edit_text_event_name.setError(null); +// edit_text_event_start.setError(null); + edit_text_event_end.setError(null); + edit_text_event_location.setError(null); + edit_text_event_description.setError(null); try { - Picasso.get().load(event.image_url).into(toolbar_image_view); - } catch (Exception e) - { + scraper.cancel(true); + scraper = null; + } catch (Exception e) { e.printStackTrace(); } + + ok_button.setEnabled(false); + layout_event_location.setEndIconVisible(false); + image_view_toolbar.setImageResource(R.drawable.ic_banner_foreground); + } + + public void update(FbEvent scraped_event) { + + this.event = scraped_event; + + edit_text_uri_input.setText(event.url); + + if (event.name.equals("")) { + edit_text_event_name.setError("no event name detected"); + } else { + edit_text_event_name.setText(event.name); + } + + if (event.start_date == null) { + edit_text_event_start.setError("no event start date detected"); + } else { + String str = FbEvent.dateTimeToString(event.start_date); + edit_text_event_start.setText(str); + } + + if (event.end_date == null) { + edit_text_event_end.setError("no event end date detected"); + } else { + String str = FbEvent.dateTimeToString(event.end_date); + edit_text_event_end.setText(str); + } + + if (event.location.equals("")) { + edit_text_event_location.setError("no event location detected"); + } else { + edit_text_event_location.setText(event.location); + layout_event_location.setEndIconVisible(true); + } + + if (event.description.equals("")) { + edit_text_event_description.setError("no event description detected"); + } else { + edit_text_event_description.setText(event.description); + } + + Picasso.get() + .load(event.image_url) + .placeholder(R.drawable.ic_banner_foreground) + .into(image_view_toolbar); + ok_button.setEnabled(true); } diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml index 668bbf2..9f108d2 100644 --- a/app/src/main/res/layout/activity_main.xml +++ b/app/src/main/res/layout/activity_main.xml @@ -3,6 +3,7 @@ - + tools:showIn="@layout/activity_main"> - + android:layout_height="wrap_content" + android:layout_marginStart="16dp" + android:layout_marginEnd="16dp" + android:layout_marginTop="32dp" + android:layout_marginBottom="64dp" - + android:divider="@drawable/divider" + android:orientation="vertical" + android:showDividers="middle"> - + app:helperTextEnabled="true"> - + android:layout_height="match_parent"> - + android:focusable="false" + android:cursorVisible="false" + android:hint="Event name" + android:inputType="textNoSuggestions" + android:singleLine="true" + android:textColorLink="@color/material_on_background_emphasis_high_type" /> + - + - - + + - + - - - - - - - + + - + - - + + - + - - + + - - - - - - + \ No newline at end of file