1
0
mirror of https://github.com/akaessens/NoFbEventScraper synced 2025-06-05 23:29:13 +02:00

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
This commit is contained in:
akaessens
2020-08-28 14:31:45 +02:00
parent 05f3ba9a33
commit 16d390094e
8 changed files with 427 additions and 568 deletions

View File

@ -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'
}

View File

@ -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);
}
}

View File

@ -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);
}
}

View File

@ -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 "";
}
}
}

View File

@ -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<Void, Void, Void> {
private String url;
private String error;
private MainActivity main;
private String input_str;
private WeakReference<MainActivity> main; // no context leak with WeakReference
private FbEvent event;
FbScraper(MainActivity main, String url) {
this.url = url;
FbScraper(WeakReference<MainActivity> 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<Void, Void, Void> {
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<Void, Void, Void> {
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);
}
}
}

View File

@ -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);
}

View File

@ -3,6 +3,7 @@
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/coordinator_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
@ -16,7 +17,7 @@
android:theme="@style/AppTheme.AppBarOverlay">
<com.google.android.material.appbar.CollapsingToolbarLayout
android:id="@+id/toolbar_layout"
android:id="@+id/layout_toolbar"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/colorPrimary"
@ -63,7 +64,7 @@
<include layout="@layout/content_main" />
<com.google.android.material.bottomappbar.BottomAppBar
android:id="@+id/bottomButtonLayout"
android:id="@+id/bottom_appbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="bottom"

View File

@ -1,59 +1,50 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.core.widget.NestedScrollView xmlns:android="http://schemas.android.com/apk/res/android"
<androidx.core.widget.NestedScrollView
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/nested_scroll_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:animateLayoutChanges="false"
app:layout_behavior="@string/appbar_scrolling_view_behavior"
tools:context=".MainActivity"
tools:showIn="@layout/activity_main"
android:id="@+id/nested_scroll_view" >
tools:showIn="@layout/activity_main">
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/constraint_layout"
<LinearLayout
android:id="@+id/linear_layout"
android:layout_width="match_parent"
android:layout_height="match_parent">
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginEnd="16dp"
android:layout_marginTop="32dp"
android:layout_marginBottom="64dp"
<LinearLayout
android:id="@+id/linearLayout4"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginTop="16dp"
android:layout_marginEnd="16dp"
android:gravity="center"
android:orientation="vertical"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
android:divider="@drawable/divider"
android:orientation="vertical"
android:showDividers="middle">
</LinearLayout>
<com.google.android.material.textfield.TextInputLayout
android:id="@+id/textInputLayout"
style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginTop="16dp"
android:id="@+id/layout_uri_input"
style="@style/Widget.MaterialComponents.TextInputLayout.FilledBox"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginEnd="16dp"
app:endIconCheckable="false"
app:endIconDrawable="@drawable/ic_backspace_black"
app:endIconMode="custom"
app:errorIconDrawable="@drawable/ic_backspace_black"
app:endIconMode="custom"
app:helperText="@string/add_link_helper"
app:helperTextEnabled="true"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/linearLayout4">
app:helperTextEnabled="true">
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/field_uri_input"
android:id="@+id/edit_text_uri_input"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:autoLink="web"
android:clickable="true"
android:cursorVisible="true"
android:hint="@string/add_link_hint"
android:inputType="textNoSuggestions"
@ -61,127 +52,94 @@
android:textColorLink="@color/material_on_background_emphasis_high_type" />
</com.google.android.material.textfield.TextInputLayout>
<LinearLayout
android:id="@+id/scrollView"
<com.google.android.material.textfield.TextInputLayout
style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginTop="16dp"
android:layout_marginEnd="16dp"
android:layout_marginBottom="16dp"
app:layout_constraintBottom_toTopOf="@+id/spacer"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/textInputLayout">
android:layout_height="match_parent">
<LinearLayout
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/edit_text_event_name"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:divider="@drawable/divider"
android:orientation="vertical"
android:showDividers="middle">
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" />
</com.google.android.material.textfield.TextInputLayout>
<com.google.android.material.textfield.TextInputLayout
style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox"
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.google.android.material.textfield.TextInputLayout
style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox"
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/field_event_name"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:clickable="true"
android:cursorVisible="true"
android:hint="Event name"
android:inputType="textNoSuggestions"
android:singleLine="true"
android:textColorLink="@color/material_on_background_emphasis_high_type" />
</com.google.android.material.textfield.TextInputLayout>
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/edit_text_event_start"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:focusable="false"
android:cursorVisible="false"
android:hint="Event start"
android:inputType="textNoSuggestions"
android:singleLine="true" />
</com.google.android.material.textfield.TextInputLayout>
<com.google.android.material.textfield.TextInputLayout
style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox"
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.google.android.material.textfield.TextInputLayout
style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox"
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/field_event_start"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:clickable="true"
android:cursorVisible="true"
android:inputType="textNoSuggestions"
android:hint="Event start"
android:singleLine="true" />
</com.google.android.material.textfield.TextInputLayout>
<com.google.android.material.textfield.TextInputLayout
style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox"
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/field_event_end"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:clickable="true"
android:cursorVisible="true"
android:inputType="textNoSuggestions"
android:hint="Event end"
android:singleLine="true" />
</com.google.android.material.textfield.TextInputLayout>
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/edit_text_event_end"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:focusable="false"
android:cursorVisible="false"
android:hint="Event end"
android:inputType="textNoSuggestions"
android:singleLine="true" />
</com.google.android.material.textfield.TextInputLayout>
<com.google.android.material.textfield.TextInputLayout
style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox"
android:id="@+id/location_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:endIconDrawable="@drawable/ic_add_location"
app:endIconMode="custom">
<com.google.android.material.textfield.TextInputLayout
android:id="@+id/layout_event_location"
style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:endIconDrawable="@drawable/ic_add_location"
app:endIconMode="custom">
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/field_event_location"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:autoLink="map"
android:clickable="true"
android:cursorVisible="true"
android:hint="Event location"
android:inputType="textNoSuggestions"
android:singleLine="true" />
</com.google.android.material.textfield.TextInputLayout>
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/edit_text_event_location"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:autoLink="map"
android:focusable="false"
android:cursorVisible="false"
android:hint="Event location"
android:inputType="textNoSuggestions"
android:singleLine="true" />
</com.google.android.material.textfield.TextInputLayout>
<com.google.android.material.textfield.TextInputLayout
style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox"
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.google.android.material.textfield.TextInputLayout
style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox"
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/field_event_description"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:autoLink="web"
android:clickable="true"
android:cursorVisible="true"
android:hint="Event description"
android:inputType="textNoSuggestions|textMultiLine"
android:singleLine="false"
android:textColorLink="@color/material_on_background_emphasis_high_type" />
</com.google.android.material.textfield.TextInputLayout>
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/edit_text_event_description"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:autoLink="web"
android:focusable="false"
android:cursorVisible="false"
android:hint="Event description"
android:inputType="textNoSuggestions|textMultiLine"
android:singleLine="false"
android:textColorLink="@color/material_on_background_emphasis_high_type" />
</com.google.android.material.textfield.TextInputLayout>
</LinearLayout>
</LinearLayout>
<Space
android:id="@+id/spacer"
android:layout_width="wrap_content"
android:layout_height="48dp"
android:layout_marginStart="16dp"
android:layout_marginEnd="16dp"
app:layout_constraintBottom_toBottomOf="@id/constraint_layout"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
</LinearLayout>
</androidx.core.widget.NestedScrollView>