Compare commits
51 Commits
Author | SHA1 | Date | |
---|---|---|---|
1570742462 | |||
0950da98e1 | |||
15ef35ba6c | |||
55e7ad44d8 | |||
2d3d2a2ab6 | |||
dd36c1fb00 | |||
268a6bc650 | |||
f9a711300e | |||
793a9e3549 | |||
ec62cb6347 | |||
023b7f951a | |||
4e319d3807 | |||
41eac31dba | |||
6c0c2d23fe | |||
16d390094e | |||
05f3ba9a33 | |||
57b00e2e57 | |||
9fd1a975ec | |||
d60717f0b7 | |||
98ab900b3d | |||
5af23c1962 | |||
868a5340e9 | |||
c3d1227d4d | |||
f9843b63bf | |||
fc9fb169ef | |||
a1c7720836 | |||
9ab18b496f | |||
40a2c7d18f | |||
fd874d7cb0 | |||
eafa1bfc1b | |||
bc9cf04f10 | |||
ac98a4a43c | |||
b9f9038f6e | |||
22591424fa | |||
e08497fd2d | |||
7c975b8d7e | |||
423642f7f7 | |||
8a1f5f8c53 | |||
ef42b404e9 | |||
dbde1188dc | |||
d37a8362a6 | |||
53ff8e4609 | |||
b88d429af1 | |||
bbadfef7d3 | |||
3f37c9b2b3 | |||
25f763ae1f | |||
3c119f8209 | |||
c9db3d61cd | |||
43365350b7 | |||
ed27561506 | |||
5e90eea230 |
21
.github/workflows/android.yml
vendored
Normal file
@ -0,0 +1,21 @@
|
||||
name: Android CI
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ master ]
|
||||
pull_request:
|
||||
branches: [ master ]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: set up JDK 1.8
|
||||
uses: actions/setup-java@v1
|
||||
with:
|
||||
java-version: 1.8
|
||||
- name: Build with Gradle
|
||||
run: ./gradlew build
|
1
.gitignore
vendored
@ -14,3 +14,4 @@ app/release
|
||||
/captures
|
||||
.externalNativeBuild
|
||||
.cxx
|
||||
.idea
|
||||
|
1
.idea/.name
generated
@ -1 +0,0 @@
|
||||
NoFb Event Scraper
|
116
.idea/codeStyles/Project.xml
generated
@ -1,116 +0,0 @@
|
||||
<component name="ProjectCodeStyleConfiguration">
|
||||
<code_scheme name="Project" version="173">
|
||||
<codeStyleSettings language="XML">
|
||||
<indentOptions>
|
||||
<option name="CONTINUATION_INDENT_SIZE" value="4" />
|
||||
</indentOptions>
|
||||
<arrangement>
|
||||
<rules>
|
||||
<section>
|
||||
<rule>
|
||||
<match>
|
||||
<AND>
|
||||
<NAME>xmlns:android</NAME>
|
||||
<XML_ATTRIBUTE />
|
||||
<XML_NAMESPACE>^$</XML_NAMESPACE>
|
||||
</AND>
|
||||
</match>
|
||||
</rule>
|
||||
</section>
|
||||
<section>
|
||||
<rule>
|
||||
<match>
|
||||
<AND>
|
||||
<NAME>xmlns:.*</NAME>
|
||||
<XML_ATTRIBUTE />
|
||||
<XML_NAMESPACE>^$</XML_NAMESPACE>
|
||||
</AND>
|
||||
</match>
|
||||
<order>BY_NAME</order>
|
||||
</rule>
|
||||
</section>
|
||||
<section>
|
||||
<rule>
|
||||
<match>
|
||||
<AND>
|
||||
<NAME>.*:id</NAME>
|
||||
<XML_ATTRIBUTE />
|
||||
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
|
||||
</AND>
|
||||
</match>
|
||||
</rule>
|
||||
</section>
|
||||
<section>
|
||||
<rule>
|
||||
<match>
|
||||
<AND>
|
||||
<NAME>.*:name</NAME>
|
||||
<XML_ATTRIBUTE />
|
||||
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
|
||||
</AND>
|
||||
</match>
|
||||
</rule>
|
||||
</section>
|
||||
<section>
|
||||
<rule>
|
||||
<match>
|
||||
<AND>
|
||||
<NAME>name</NAME>
|
||||
<XML_ATTRIBUTE />
|
||||
<XML_NAMESPACE>^$</XML_NAMESPACE>
|
||||
</AND>
|
||||
</match>
|
||||
</rule>
|
||||
</section>
|
||||
<section>
|
||||
<rule>
|
||||
<match>
|
||||
<AND>
|
||||
<NAME>style</NAME>
|
||||
<XML_ATTRIBUTE />
|
||||
<XML_NAMESPACE>^$</XML_NAMESPACE>
|
||||
</AND>
|
||||
</match>
|
||||
</rule>
|
||||
</section>
|
||||
<section>
|
||||
<rule>
|
||||
<match>
|
||||
<AND>
|
||||
<NAME>.*</NAME>
|
||||
<XML_ATTRIBUTE />
|
||||
<XML_NAMESPACE>^$</XML_NAMESPACE>
|
||||
</AND>
|
||||
</match>
|
||||
<order>BY_NAME</order>
|
||||
</rule>
|
||||
</section>
|
||||
<section>
|
||||
<rule>
|
||||
<match>
|
||||
<AND>
|
||||
<NAME>.*</NAME>
|
||||
<XML_ATTRIBUTE />
|
||||
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
|
||||
</AND>
|
||||
</match>
|
||||
<order>ANDROID_ATTRIBUTE_ORDER</order>
|
||||
</rule>
|
||||
</section>
|
||||
<section>
|
||||
<rule>
|
||||
<match>
|
||||
<AND>
|
||||
<NAME>.*</NAME>
|
||||
<XML_ATTRIBUTE />
|
||||
<XML_NAMESPACE>.*</XML_NAMESPACE>
|
||||
</AND>
|
||||
</match>
|
||||
<order>BY_NAME</order>
|
||||
</rule>
|
||||
</section>
|
||||
</rules>
|
||||
</arrangement>
|
||||
</codeStyleSettings>
|
||||
</code_scheme>
|
||||
</component>
|
20
.idea/gradle.xml
generated
@ -1,20 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="GradleMigrationSettings" migrationVersion="1" />
|
||||
<component name="GradleSettings">
|
||||
<option name="linkedExternalProjectsSettings">
|
||||
<GradleProjectSettings>
|
||||
<option name="testRunner" value="PLATFORM" />
|
||||
<option name="distributionType" value="DEFAULT_WRAPPED" />
|
||||
<option name="externalProjectPath" value="$PROJECT_DIR$" />
|
||||
<option name="modules">
|
||||
<set>
|
||||
<option value="$PROJECT_DIR$" />
|
||||
<option value="$PROJECT_DIR$/app" />
|
||||
</set>
|
||||
</option>
|
||||
<option name="resolveModulePerSourceSet" value="false" />
|
||||
</GradleProjectSettings>
|
||||
</option>
|
||||
</component>
|
||||
</project>
|
9
.idea/misc.xml
generated
@ -1,9 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ProjectRootManager" version="2" languageLevel="JDK_1_7" project-jdk-name="1.8" project-jdk-type="JavaSDK">
|
||||
<output url="file://$PROJECT_DIR$/build/classes" />
|
||||
</component>
|
||||
<component name="ProjectType">
|
||||
<option name="id" value="Android" />
|
||||
</component>
|
||||
</project>
|
12
.idea/runConfigurations.xml
generated
@ -1,12 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="RunConfigurationProducerService">
|
||||
<option name="ignoredProducers">
|
||||
<set>
|
||||
<option value="org.jetbrains.plugins.gradle.execution.test.runner.AllInPackageGradleConfigurationProducer" />
|
||||
<option value="org.jetbrains.plugins.gradle.execution.test.runner.TestClassGradleConfigurationProducer" />
|
||||
<option value="org.jetbrains.plugins.gradle.execution.test.runner.TestMethodGradleConfigurationProducer" />
|
||||
</set>
|
||||
</option>
|
||||
</component>
|
||||
</project>
|
6
.idea/vcs.xml
generated
@ -1,6 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="VcsDirectoryMappings">
|
||||
<mapping directory="$PROJECT_DIR$" vcs="Git" />
|
||||
</component>
|
||||
</project>
|
14
README.md
@ -1,4 +1,8 @@
|
||||
# NoFbEventScraper
|
||||

|
||||
|
||||
<img src="https://github.com/akaessens/NoFbEventScraper/raw/master/fastlane/metadata/android/en-US/images/featureGraphic.png" alt="Feature Graphic" width="max-width">
|
||||
|
||||
# NoFb Event Scraper
|
||||
|
||||
This application was developed to be used without a facebook account.
|
||||
|
||||
@ -6,7 +10,11 @@ Therefore it does not use the facebook API.
|
||||
Instead it opens the facebook event URI and downloads the website source code.
|
||||
This source contains the information which is used to create a calendar entry.
|
||||
|
||||
# Download
|
||||
Currently this application is in the submitting process to FDroid. see also [#2](/../../issues/2).
|
||||
|
||||
# Screenshot
|
||||
Until it is published at FDroid, use [release v0.3.1](https://github.com/akaessens/NoFbEventScraper/releases/download/v0.3.1/app-release.apk).
|
||||
|
||||

|
||||
# Screenshots
|
||||
|
||||
<img src="https://github.com/akaessens/NoFbEventScraper/raw/master/fastlane/metadata/android/en-US/images/phoneScreenshots/1.png" alt="Screenshot 1" width="200"> <img src="https://github.com/akaessens/NoFbEventScraper/raw/master/fastlane/metadata/android/en-US/images/phoneScreenshots/2.png" alt="Screenshot 2" width="200"> <img src="https://github.com/akaessens/NoFbEventScraper/raw/master/fastlane/metadata/android/en-US/images/phoneScreenshots/3.png" alt="Screenshot 3" width="200"> <img src="https://github.com/akaessens/NoFbEventScraper/raw/master/fastlane/metadata/android/en-US/images/phoneScreenshots/4.png" alt="Screenshot 4" width="200">
|
||||
|
@ -8,8 +8,8 @@ android {
|
||||
applicationId "com.akdev.nofbeventscraper"
|
||||
minSdkVersion 26
|
||||
targetSdkVersion 29
|
||||
versionCode 1
|
||||
versionName "0.1.0"
|
||||
versionCode 7
|
||||
versionName "0.3.1"
|
||||
|
||||
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||
}
|
||||
@ -24,18 +24,23 @@ android {
|
||||
}
|
||||
|
||||
dependencies {
|
||||
'androidx.coordinatorlayout:coordinatorlayout:1.1.0'
|
||||
|
||||
implementation fileTree(dir: 'libs', include: ['*.jar'])
|
||||
|
||||
implementation 'androidx.appcompat:appcompat:1.1.0'
|
||||
implementation 'com.google.android.material:material:1.1.0'
|
||||
implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
|
||||
implementation 'androidx.navigation:navigation-fragment:2.2.1'
|
||||
implementation 'androidx.navigation:navigation-ui:2.2.1'
|
||||
implementation 'androidx.appcompat:appcompat:1.2.0'
|
||||
implementation 'com.google.android.material:material:1.2.0'
|
||||
implementation 'androidx.constraintlayout:constraintlayout:2.0.1'
|
||||
implementation 'androidx.navigation:navigation-fragment:2.3.0'
|
||||
implementation 'androidx.navigation:navigation-ui:2.3.0'
|
||||
|
||||
// jsoup HTML parser library @ https://jsoup.org/
|
||||
implementation 'org.jsoup:jsoup:1.11.1'
|
||||
implementation 'org.jsoup:jsoup:1.13.1'
|
||||
|
||||
implementation 'com.squareup.picasso:picasso:2.71828'
|
||||
implementation 'androidx.preference:preference:1.1.1'
|
||||
|
||||
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'
|
||||
}
|
||||
|
@ -0,0 +1,87 @@
|
||||
package com.akdev.nofbeventscraper;
|
||||
|
||||
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() {
|
||||
|
||||
|
||||
FbScraper scraper = new FbScraper(null, "");
|
||||
|
||||
String exp = "Deutschland";
|
||||
String json = "{'@type': 'Place', 'name': 'Deutschland'}";
|
||||
String act = scraper.fixLocation(json);
|
||||
assertEquals(exp, act);
|
||||
|
||||
exp = "Example name, Example Street 1, 12345 Example city";
|
||||
json = "{'@type': 'Place', 'name': 'Example name', 'address': {'@type': 'PostalAddress', 'addressCountry': 'DE', 'addressLocality': 'Example city', 'postalCode': '12345', 'streetAddress': 'Example Street 1'}}";
|
||||
act = scraper.fixLocation(json);
|
||||
assertEquals(exp, act);
|
||||
|
||||
exp = "";
|
||||
json = "";
|
||||
act = scraper.fixLocation(json);
|
||||
assertEquals(exp, act);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTimezone() {
|
||||
|
||||
FbScraper scraper = new FbScraper(null, "");
|
||||
|
||||
String exp = "2020-10-23T05:00+02:00";
|
||||
String in = "2020-10-23T05:00:00+0200";
|
||||
String act = scraper.toZonedDateTime(in).toString();
|
||||
assertEquals(exp, act);
|
||||
|
||||
|
||||
exp = null;
|
||||
in = "";
|
||||
ZonedDateTime act2 = scraper.toZonedDateTime(in);
|
||||
assertEquals(exp, act2);
|
||||
}
|
||||
|
||||
@Test
|
||||
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.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.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);
|
||||
}
|
||||
}
|
@ -11,7 +11,25 @@
|
||||
android:roundIcon="@mipmap/ic_launcher_round"
|
||||
android:supportsRtl="true"
|
||||
android:theme="@style/AppTheme">
|
||||
<activity android:name=".AboutActivity"></activity>
|
||||
|
||||
<activity android:name=".SettingsActivity"
|
||||
android:label="@string/action_settings" >
|
||||
<meta-data
|
||||
android:name="android.support.PARENT_ACTIVITY"
|
||||
android:value=".MainActivity"/>
|
||||
</activity>
|
||||
<activity android:name=".HelpActivity"
|
||||
android:label="@string/action_help" >
|
||||
<meta-data
|
||||
android:name="android.support.PARENT_ACTIVITY"
|
||||
android:value=".MainActivity"/>
|
||||
</activity>
|
||||
<activity android:name=".AboutActivity"
|
||||
android:label="@string/action_about" >
|
||||
<meta-data
|
||||
android:name="android.support.PARENT_ACTIVITY"
|
||||
android:value=".MainActivity"/>
|
||||
</activity>
|
||||
<activity
|
||||
android:name=".MainActivity"
|
||||
android:label="@string/app_name"
|
||||
|
11
app/src/main/assets/about.html
Normal file
@ -0,0 +1,11 @@
|
||||
<!doctype html>
|
||||
<h3>Description</h3>
|
||||
<p>This application was developed to be used without a facebook account. Therefore it does not use the facebook API. Instead it opens the facebook event URI and downloads the website source code. This source contains the information which is used to create a calendar entry.</p>
|
||||
<h3>Open Source</h3>
|
||||
<p>The source code for this application is available at <a href=" https://github.com/akaessens/NoFbEventScraper">GitHub</a>.<strong><br /></strong></p>
|
||||
<p>If you encounter an issue, please report it to me anonymously at the <a href="https://gitreports.com/issue/akaessens/NoFbEventScraper">Bugtracker</a> or directly at <a href="https://github.com/akaessens/NoFbEventScraper/issues">GitHub</a>.</p>
|
||||
<h3>Legal</h3>
|
||||
<p>This application is intended for saving single, publicly available events into a personal calendar. Do not use it to automatically collect data and comply with facebook's <a href="http://www.facebook.com/apps/site_scraping_tos_terms.php">Automated Data Collection Terms</a>.</p>
|
||||
<h3>Donations</h3>
|
||||
<p>I develop this application in my free time. If you like it, you can donate at <a href="https://www.paypal.me/andreaskaessens">PayPal</a>.</p>
|
||||
<p><a title="PayPal" href="https://www.paypal.me/andreaskaessens"><img src="https://www.paypalobjects.com/webstatic/de_DE/i/de-pp-logo-100px.png" /></a></p>
|
14
app/src/main/assets/help.html
Normal file
@ -0,0 +1,14 @@
|
||||
<!doctype html>
|
||||
<h3>What links can be used with this app?</h3>
|
||||
<p>All facebook subdomains are supported, whether mobile (m.facebook.com) or language-specific (de-de.facebook.com). The link must contain an event ID.</p>
|
||||
<h3>How to use this application?</h3>
|
||||
<ul>
|
||||
<li><strong>Paste button</strong>: paste a copied link from the clipboard into the URL bar.</li>
|
||||
<li><strong>Share to</strong>: Android's built-in share-function, e.g. from a browser.</li>
|
||||
<li><strong>Open with</strong>: Android's built-in open-with-function, e.g. when clicking on a link in a messenger.</li>
|
||||
</ul>
|
||||
<h3>Why does event X not work?</h3>
|
||||
<p>This app relies on event information that is publicy available. If the event does not offer for example the location without a login, it will not be available in this application. Events with multiple instances are problematic because they do not provide the correct start and end date when scraping from m.facebook.com.</p>
|
||||
<p>If you encounter issues with a specific event, please let me know via the <a href="https://gitreports.com/issue/akaessens/NoFbEventScraper">anonymous bugtracker</a> or at the <a href="https://github.com/akaessens/NoFbEventScraper/issues/">GitHub issue page</a>.</p>
|
||||
<h3>Is this compatible with my calendar app?</h3>
|
||||
<p>Yes. This application makes use of application independent calendar functions, which makes it compatible to every calendar app. However, i recommend <a href="https://play.google.com/store/apps/details?id=ws.xsoh.etar&hl=de">Etar Calendar</a> because it is Open Source.</p>
|
Before Width: | Height: | Size: 10 KiB After Width: | Height: | Size: 14 KiB |
@ -1,8 +1,15 @@
|
||||
package com.akdev.nofbeventscraper;
|
||||
|
||||
import androidx.appcompat.app.ActionBar;
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
import androidx.appcompat.widget.Toolbar;
|
||||
|
||||
import android.content.Intent;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.view.View;
|
||||
import android.webkit.WebView;
|
||||
import android.widget.ImageView;
|
||||
|
||||
public class AboutActivity extends AppCompatActivity {
|
||||
|
||||
@ -10,5 +17,15 @@ public class AboutActivity extends AppCompatActivity {
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.activity_about);
|
||||
ActionBar action_bar = getSupportActionBar();
|
||||
if (action_bar != null) {
|
||||
action_bar.setDisplayHomeAsUpEnabled(true);
|
||||
}
|
||||
|
||||
WebView webview_about = findViewById(R.id.webview_about);
|
||||
|
||||
webview_about.loadUrl("file:////android_asset/about.html");
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
@ -1,14 +1,27 @@
|
||||
package com.akdev.nofbeventscraper;
|
||||
|
||||
public class FbEvent {
|
||||
public String name;
|
||||
public String start_date;
|
||||
public String end_date;
|
||||
public String description;
|
||||
public String location;
|
||||
public String image_url;
|
||||
import java.time.ZonedDateTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.time.format.FormatStyle;
|
||||
|
||||
public FbEvent (String name, String start_date, String end_date, String description, String location, String image_url) {
|
||||
/**
|
||||
* Objects of this class store immutable information about
|
||||
* a single event that was created by the FbScraper.
|
||||
*/
|
||||
public class FbEvent {
|
||||
|
||||
public final String url;
|
||||
public final String name;
|
||||
public final ZonedDateTime start_date;
|
||||
public final ZonedDateTime end_date;
|
||||
public final String description;
|
||||
public final String location;
|
||||
public final String image_url;
|
||||
|
||||
|
||||
public FbEvent(String url, String name, ZonedDateTime start_date, ZonedDateTime end_date,
|
||||
String description, String location, String image_url) {
|
||||
this.url = url;
|
||||
this.name = name;
|
||||
this.start_date = start_date;
|
||||
this.end_date = end_date;
|
||||
@ -16,4 +29,34 @@ public class FbEvent {
|
||||
this.location = location;
|
||||
this.image_url = image_url;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts datetime to epoch.
|
||||
*
|
||||
* @param zoned_date_time ZonedDateTime object
|
||||
* @return Event begin time in milliseconds from the epoch for calendar intent or null
|
||||
*/
|
||||
static Long dateTimeToEpoch(ZonedDateTime zoned_date_time) {
|
||||
try {
|
||||
return zoned_date_time.toEpochSecond() * 1000;
|
||||
} catch (Exception e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a RFC formatted String representation of a ZonedDateTime
|
||||
*
|
||||
* @param zoned_date_time
|
||||
* @return RFC-1123 formatted String of zoned_date_time or empty String
|
||||
*/
|
||||
static String dateTimeToString(ZonedDateTime zoned_date_time) {
|
||||
try {
|
||||
return DateTimeFormatter
|
||||
.RFC_1123_DATE_TIME
|
||||
.format(zoned_date_time);
|
||||
} catch (Exception e) {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,15 +1,11 @@
|
||||
package com.akdev.nofbeventscraper;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.Context;
|
||||
import android.content.SharedPreferences;
|
||||
import android.os.AsyncTask;
|
||||
import android.text.Editable;
|
||||
import android.text.SpannableStringBuilder;
|
||||
import android.util.Log;
|
||||
import android.view.View;
|
||||
import android.widget.Toast;
|
||||
|
||||
import com.google.android.material.textfield.TextInputEditText;
|
||||
import androidx.preference.PreferenceManager;
|
||||
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
@ -17,102 +13,222 @@ 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;
|
||||
|
||||
/**
|
||||
* This class can asynchronously scrape public facebook events
|
||||
* and gather the most important information. It is stored in a FbEvent object.
|
||||
*/
|
||||
public class FbScraper extends AsyncTask<Void, Void, Void> {
|
||||
|
||||
private String url;
|
||||
private String error;
|
||||
private MainActivity main;
|
||||
private String input_url;
|
||||
private WeakReference<MainActivity> main; // no context leak with WeakReference
|
||||
private FbEvent event;
|
||||
|
||||
FbScraper(MainActivity main, String url) {
|
||||
this.url = url;
|
||||
/**
|
||||
* Constructor with WeakReference to the main activity, to update it's text fields.
|
||||
*
|
||||
* @param main WeakReference of main activity to prevent context leak
|
||||
* @param input_url Input url to scrape from
|
||||
*/
|
||||
FbScraper(WeakReference<MainActivity> main, String input_url) {
|
||||
this.main = main;
|
||||
this.input_url = input_url;
|
||||
}
|
||||
|
||||
/**
|
||||
* Strips the facebook event link of the input url.
|
||||
*
|
||||
* @param url input url
|
||||
* @return facebook event url String if one was found
|
||||
* @throws URISyntaxException if event not found
|
||||
* @throws MalformedURLException
|
||||
*/
|
||||
protected String fixURI(String url) throws URISyntaxException, MalformedURLException {
|
||||
|
||||
// check for url format
|
||||
new URL(url).toURI();
|
||||
|
||||
String regex = "(facebook.com/events/[0-9]*)(/\\?event_time_id=[0-9]*)?";
|
||||
|
||||
Pattern pattern = Pattern.compile(regex);
|
||||
Matcher matcher = pattern.matcher(url);
|
||||
|
||||
if (matcher.find()) {
|
||||
|
||||
String url_prefix = "https://m.";
|
||||
if (main != null){
|
||||
SharedPreferences shared_prefs = PreferenceManager.getDefaultSharedPreferences(main.get());
|
||||
url_prefix = shared_prefs.getString("url_preference", url_prefix);
|
||||
}
|
||||
|
||||
// rewrite url to m.facebook and dismiss any query strings or referrals
|
||||
String ret = url_prefix + matcher.group(1);
|
||||
if (matcher.group(2) != null) {
|
||||
ret += matcher.group(2);
|
||||
}
|
||||
return ret;
|
||||
} else {
|
||||
throw new URISyntaxException(url, "Does not contain event.");
|
||||
}
|
||||
|
||||
}
|
||||
private String readFromLocJson(String location_json) {
|
||||
|
||||
String name = "";
|
||||
String street_address = "";
|
||||
String postal_code = "";
|
||||
String address_locality = "";
|
||||
/**
|
||||
* Strips the event location from the json string.
|
||||
* This can be a name only or a complete postal address.
|
||||
* @param location_json JSON formatted string
|
||||
* @return String representation of the location.
|
||||
*/
|
||||
protected String fixLocation(String location_json) {
|
||||
|
||||
String location_name = "";
|
||||
|
||||
try {
|
||||
JSONObject reader = new JSONObject(location_json);
|
||||
|
||||
name = reader.getString("name");
|
||||
|
||||
location_name = reader.getString("name");
|
||||
JSONObject address = reader.getJSONObject("address");
|
||||
street_address = ", " + address.getString("streetAddress");
|
||||
postal_code = ", " + address.getString("postalCode");
|
||||
address_locality = " " + address.getString("addressLocality");
|
||||
|
||||
String type = address.getString("@type");
|
||||
|
||||
if (type.equals("PostalAddress")) {
|
||||
String postal_code = address.getString("postalCode");
|
||||
String address_locality = address.getString("addressLocality");
|
||||
String street_address = address.getString("streetAddress");
|
||||
// included in locality
|
||||
//String address_country = address.getString("addressCountry");
|
||||
|
||||
return location_name + ", "
|
||||
+ street_address + ", "
|
||||
+ postal_code + " "
|
||||
+ address_locality;
|
||||
} else {
|
||||
return location_name;
|
||||
}
|
||||
|
||||
} catch (JSONException e) {
|
||||
e.printStackTrace();
|
||||
return location_name;
|
||||
}
|
||||
|
||||
return name + street_address + postal_code + address_locality;
|
||||
}
|
||||
|
||||
private String fixTimezone(String time_in) {
|
||||
/**
|
||||
* Parses a time string from the facebook event.
|
||||
* Corrects format to ISO date time and parse into ZonedDateTime
|
||||
*
|
||||
* @param time_in time string from the event
|
||||
* @return ZonedDateTime parsed from input or null
|
||||
*/
|
||||
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 null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Replaces all occurrences of a facebook internal links in
|
||||
* an event description into an actual URL.
|
||||
*
|
||||
* @param description_in description string from the event
|
||||
* @return corrected String with internal links resolved
|
||||
*/
|
||||
protected String fixDescriptionLinks(String description_in) {
|
||||
try {
|
||||
/* @[152580919265:274:SiteDescription]
|
||||
* to
|
||||
* SiteDescription [m.facebook.com/152580919265] */
|
||||
|
||||
return description_in.replaceAll("@\\[([0-9]{10,}):[0-9]{3}:([^]]*)]",
|
||||
"$2 [m.facebook.com/$1]");
|
||||
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
return description_in;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Read a single field from a JSONObject
|
||||
* @param reader JSONObject to read from
|
||||
* @param field Which field to read
|
||||
* @return String of the value of the field or empty string
|
||||
*/
|
||||
private String readFromJson(JSONObject reader, String field) {
|
||||
try {
|
||||
return reader.getString(field);
|
||||
}
|
||||
catch (Exception e) {
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
return null;
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Started by scraper.execute().
|
||||
* Gets the HTML doc from the input string and scrapes the event information from it.
|
||||
* @param voids
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
protected Void doInBackground(Void... voids) {
|
||||
|
||||
Document document = null;
|
||||
|
||||
try {
|
||||
document = Jsoup.connect(url).get();
|
||||
String url = fixURI(input_url);
|
||||
// use correct system user agent because of facebook ToS
|
||||
String user_agent = System.getProperty("http.agent");
|
||||
Document document = Jsoup.connect(url).userAgent(user_agent).get();
|
||||
|
||||
try {
|
||||
String json = document.select("script[type = application/ld+json]").first().data();
|
||||
|
||||
JSONObject reader = new JSONObject(json);
|
||||
|
||||
String event_name = readFromJson(reader, "name");
|
||||
String event_start = fixTimezone(readFromJson(reader, "startDate"));
|
||||
String event_end = fixTimezone(readFromJson(reader, "endDate"));
|
||||
|
||||
String event_description = readFromJson(reader, "description");
|
||||
String location_json = readFromJson(reader, "location");
|
||||
|
||||
|
||||
String location = readFromLocJson(location_json);
|
||||
|
||||
if (event_name == null) {
|
||||
this.event = null;
|
||||
throw new Exception();
|
||||
} else {
|
||||
this.event = new FbEvent(event_name, event_start, event_end, event_description, location, null);
|
||||
}
|
||||
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
this.error = "Error: Scraping event data failed";
|
||||
if (document == null) {
|
||||
throw new IOException();
|
||||
}
|
||||
String json = document
|
||||
.select("script[type = application/ld+json]")
|
||||
.first().data();
|
||||
|
||||
JSONObject reader = new JSONObject(json);
|
||||
|
||||
event = new FbEvent(
|
||||
url,
|
||||
readFromJson(reader, "name"),
|
||||
toZonedDateTime(readFromJson(reader, "startDate")),
|
||||
toZonedDateTime(readFromJson(reader, "endDate")),
|
||||
fixDescriptionLinks(readFromJson(reader, "description")),
|
||||
fixLocation(readFromJson(reader, "location")),
|
||||
readFromJson(reader, "image")
|
||||
);
|
||||
|
||||
} catch (URISyntaxException | MalformedURLException e) {
|
||||
e.printStackTrace();
|
||||
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: URL not available";
|
||||
this.error = "Error: Unable to connect.";
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
this.error = "Error: Unknown Error.";
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@ -121,15 +237,21 @@ public class FbScraper extends AsyncTask<Void, Void, Void> {
|
||||
super.onPreExecute();
|
||||
}
|
||||
|
||||
/**
|
||||
* When scraping is finished, main activity will be updated.
|
||||
* If an error occurred, main activity is given an error string.
|
||||
* @param aVoid
|
||||
*/
|
||||
protected void onPostExecute(Void aVoid) {
|
||||
super.onPostExecute(aVoid);
|
||||
|
||||
if (this.event != null) {
|
||||
this.main.update(event);
|
||||
}
|
||||
else {
|
||||
main.toast(error);
|
||||
this.main.clear(false);
|
||||
if (main != null) {
|
||||
if (this.event != null) {
|
||||
main.get().update(event);
|
||||
} else {
|
||||
main.get().error(error);
|
||||
main.get().clear(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,25 @@
|
||||
package com.akdev.nofbeventscraper;
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.webkit.WebView;
|
||||
|
||||
import androidx.appcompat.app.ActionBar;
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
|
||||
public class HelpActivity extends AppCompatActivity {
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.activity_help);
|
||||
ActionBar action_bar = getSupportActionBar();
|
||||
if (action_bar != null) {
|
||||
action_bar.setDisplayHomeAsUpEnabled(true);
|
||||
}
|
||||
|
||||
WebView webview_help = findViewById(R.id.webview_help);
|
||||
|
||||
webview_help.loadUrl("file:////android_asset/help.html");
|
||||
|
||||
}
|
||||
}
|
@ -1,41 +1,53 @@
|
||||
package com.akdev.nofbeventscraper;
|
||||
|
||||
import android.app.AlertDialog;
|
||||
import android.content.ClipboardManager;
|
||||
import android.content.Context;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.Intent;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
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;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
import android.widget.Button;
|
||||
import android.widget.Toast;
|
||||
import android.widget.ImageView;
|
||||
|
||||
import java.net.URL;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.ZoneId;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
import androidx.appcompat.view.menu.MenuBuilder;
|
||||
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.lang.ref.WeakReference;
|
||||
import java.util.Objects;
|
||||
|
||||
import static com.akdev.nofbeventscraper.FbEvent.dateTimeToEpoch;
|
||||
|
||||
public class MainActivity extends AppCompatActivity {
|
||||
|
||||
private Button paste_button;
|
||||
private Button cancel_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;
|
||||
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) {
|
||||
@ -44,17 +56,55 @@ public class MainActivity extends AppCompatActivity {
|
||||
Toolbar toolbar = findViewById(R.id.toolbar);
|
||||
setSupportActionBar(toolbar);
|
||||
|
||||
cancel_button = (Button) findViewById(R.id.cancel_button);
|
||||
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);
|
||||
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);
|
||||
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);
|
||||
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 show = true;
|
||||
int scroll_range = -1;
|
||||
|
||||
@Override
|
||||
public void onOffsetChanged(AppBarLayout app_bar_layout, int vertical_offset) {
|
||||
if (scroll_range == -1) {
|
||||
scroll_range = app_bar_layout.getTotalScrollRange();
|
||||
}
|
||||
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) {
|
||||
@ -64,57 +114,74 @@ 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();
|
||||
toast("Error: Clipboard empty");
|
||||
error("Error: Clipboard empty");
|
||||
}
|
||||
startScraping();
|
||||
}
|
||||
});
|
||||
|
||||
cancel_button.setOnClickListener(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);
|
||||
}
|
||||
});
|
||||
};
|
||||
layout_uri_input.setEndIconOnClickListener(listener);
|
||||
layout_uri_input.setErrorIconOnClickListener(listener);
|
||||
|
||||
ok_button.setOnClickListener(new View.OnClickListener() {
|
||||
/*
|
||||
* Maps button: launch maps intent
|
||||
*/
|
||||
layout_event_location.setEndIconOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View view) {
|
||||
try {
|
||||
Long start_epoch = convertTimeToEpoch(field_event_start);
|
||||
Long end_epoch = convertTimeToEpoch(field_event_end);
|
||||
String map_search = "geo:0,0?q=" + edit_text_event_location.getText();
|
||||
|
||||
String name = parseField(field_event_name);
|
||||
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" + description);
|
||||
startActivity(intent);
|
||||
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);
|
||||
}
|
||||
catch (Exception e )
|
||||
{
|
||||
e.printStackTrace();
|
||||
toast("Error: Invalid fields");
|
||||
}
|
||||
|
||||
}
|
||||
});
|
||||
|
||||
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)) {
|
||||
/*
|
||||
* Add to calendar button: launch calendar application
|
||||
*/
|
||||
ok_button.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View view) {
|
||||
|
||||
Long start_epoch = dateTimeToEpoch(event.start_date);
|
||||
Long end_epoch = dateTimeToEpoch(event.end_date);
|
||||
|
||||
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);
|
||||
}
|
||||
});
|
||||
|
||||
/*
|
||||
* 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;
|
||||
}
|
||||
@ -122,124 +189,131 @@ 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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private Long convertTimeToEpoch (TextInputEditText field) {
|
||||
try {
|
||||
String time_str = field.getText().toString();
|
||||
|
||||
LocalDateTime datetime = LocalDateTime.parse(time_str, DateTimeFormatter.ISO_OFFSET_DATE_TIME);
|
||||
return datetime.atZone(ZoneId.of("UTC")).toEpochSecond() * 1000;
|
||||
} catch (Exception e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static boolean isNumeric(String strNum) {
|
||||
if (strNum == null) {
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
double d = Double.parseDouble(strNum);
|
||||
} catch (NumberFormatException e) {
|
||||
e.printStackTrace();
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* launch the FbScraper asynchronous task with the current text in the input text field.
|
||||
*/
|
||||
public void startScraping() {
|
||||
|
||||
error(null);
|
||||
|
||||
String url = Objects.requireNonNull(edit_text_uri_input.getText()).toString();
|
||||
scraper = new FbScraper(new WeakReference<>(this), url);
|
||||
scraper.execute();
|
||||
}
|
||||
|
||||
public void error(String str) {
|
||||
layout_uri_input.setError(str);
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears all event text field strings and errors and also the input field depending if wanted.
|
||||
* Loads the default banner into the toolbar image view and disables unneeded buttons.
|
||||
*
|
||||
* @param clear_uri Choose whether to clear the input uri field, too
|
||||
*/
|
||||
public void clear(boolean clear_uri) {
|
||||
|
||||
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 {
|
||||
String str = field_uri_input.getText().toString();
|
||||
|
||||
// check for a valid uri
|
||||
new URL(str).toURI();
|
||||
|
||||
String eventId = null;
|
||||
|
||||
// check for facebook uri
|
||||
if (str.contains("facebook.com/events/")) {
|
||||
|
||||
// find event id
|
||||
String[] separated = str.split("/");
|
||||
for (int i = 0; i< separated.length; i++) {
|
||||
if (separated[i].length() > 8 && isNumeric(separated[i])) {
|
||||
eventId = separated[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (eventId == null) // no event id found
|
||||
{
|
||||
throw new Exception();
|
||||
}
|
||||
}
|
||||
else {
|
||||
throw new Exception();
|
||||
}
|
||||
|
||||
String input_uri = "https://m.facebook.com/events/"+ eventId;
|
||||
field_uri_input.setText(input_uri);
|
||||
|
||||
FbScraper scraper = new FbScraper(this, field_uri_input.getText().toString());
|
||||
scraper.execute();
|
||||
|
||||
}
|
||||
catch (Exception e) {
|
||||
scraper.cancel(true);
|
||||
scraper = null;
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
clear(true);
|
||||
toast("Invalid URL");
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
public void toast(String str) {
|
||||
Toast.makeText(this, str, Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
public void clear(boolean clearUri) {
|
||||
if (clearUri) {
|
||||
field_uri_input.setText("");
|
||||
}
|
||||
field_event_name.setText("");
|
||||
field_event_start.setText("");
|
||||
field_event_end.setText("");
|
||||
field_event_location.setText("");
|
||||
field_event_description.setText("");
|
||||
ok_button.setEnabled(false);
|
||||
layout_event_location.setEndIconVisible(false);
|
||||
image_view_toolbar.setImageResource(R.drawable.ic_banner_foreground);
|
||||
}
|
||||
|
||||
public void update(FbEvent event) {
|
||||
field_event_name.setText(event.name);
|
||||
field_event_start.setText(event.start_date);
|
||||
field_event_end.setText(event.end_date);
|
||||
field_event_location.setText(event.location);
|
||||
field_event_description.setText(event.description);
|
||||
/**
|
||||
* Updates the text fields with the event information provided.
|
||||
* If something is missing, the corresponding test field will show an error.
|
||||
*
|
||||
* @param scraped_event the event information that was scraped by FbScraper
|
||||
*/
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
@ -247,6 +321,12 @@ public class MainActivity extends AppCompatActivity {
|
||||
public boolean onCreateOptionsMenu(Menu menu) {
|
||||
// Inflate the menu; this adds items to the action bar if it is present.
|
||||
getMenuInflater().inflate(R.menu.menu_main, menu);
|
||||
|
||||
if(menu instanceof MenuBuilder){
|
||||
MenuBuilder m = (MenuBuilder) menu;
|
||||
//noinspection RestrictedApi
|
||||
m.setOptionalIconsVisible(true);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -262,6 +342,14 @@ public class MainActivity extends AppCompatActivity {
|
||||
startActivity(new Intent(this, AboutActivity.class));
|
||||
return true;
|
||||
}
|
||||
if (id == R.id.action_help) {
|
||||
startActivity(new Intent(this, HelpActivity.class));
|
||||
return true;
|
||||
}
|
||||
if (id == R.id.action_settings) {
|
||||
startActivity(new Intent(this, SettingsActivity.class));
|
||||
return true;
|
||||
}
|
||||
|
||||
return super.onOptionsItemSelected(item);
|
||||
}
|
||||
|
@ -0,0 +1,31 @@
|
||||
package com.akdev.nofbeventscraper;
|
||||
|
||||
import android.os.Bundle;
|
||||
|
||||
import androidx.appcompat.app.ActionBar;
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
import androidx.preference.PreferenceFragmentCompat;
|
||||
|
||||
public class SettingsActivity extends AppCompatActivity {
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.settings_activity);
|
||||
getSupportFragmentManager()
|
||||
.beginTransaction()
|
||||
.replace(R.id.settings, new SettingsFragment())
|
||||
.commit();
|
||||
ActionBar action_bar = getSupportActionBar();
|
||||
if (action_bar != null) {
|
||||
action_bar.setDisplayHomeAsUpEnabled(true);
|
||||
}
|
||||
}
|
||||
|
||||
public static class SettingsFragment extends PreferenceFragmentCompat {
|
||||
@Override
|
||||
public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
|
||||
setPreferencesFromResource(R.xml.root_preferences, rootKey);
|
||||
}
|
||||
}
|
||||
}
|
7
app/src/main/res/drawable/divider.xml
Normal file
@ -0,0 +1,7 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<size
|
||||
android:height="8dp"
|
||||
android:width="0dp"/>
|
||||
</shape>
|
9
app/src/main/res/drawable/ic_add_location.xml
Normal file
@ -0,0 +1,9 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:pathData="M12,2C8.14,2 5,5.14 5,9c0,5.25 7,13 7,13s7,-7.75 7,-13c0,-3.86 -3.14,-7 -7,-7zM16,10h-3v3h-2v-3L8,10L8,8h3L11,5h2v3h3v2z"
|
||||
android:fillColor="#000000"/>
|
||||
</vector>
|
9
app/src/main/res/drawable/ic_backspace_black.xml
Normal file
@ -0,0 +1,9 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:pathData="M22,3L7,3c-0.69,0 -1.23,0.35 -1.59,0.88L0.37,11.45c-0.22,0.34 -0.22,0.77 0,1.11l5.04,7.56c0.36,0.52 0.9,0.88 1.59,0.88h15c1.1,0 2,-0.9 2,-2L24,5c0,-1.1 -0.9,-2 -2,-2zM18.3,16.3c-0.39,0.39 -1.02,0.39 -1.41,0L14,13.41l-2.89,2.89c-0.39,0.39 -1.02,0.39 -1.41,0 -0.39,-0.39 -0.39,-1.02 0,-1.41L12.59,12 9.7,9.11c-0.39,-0.39 -0.39,-1.02 0,-1.41 0.39,-0.39 1.02,-0.39 1.41,0L14,10.59l2.89,-2.89c0.39,-0.39 1.02,-0.39 1.41,0 0.39,0.39 0.39,1.02 0,1.41L15.41,12l2.89,2.89c0.38,0.38 0.38,1.02 0,1.41z"
|
||||
android:fillColor="#000000"/>
|
||||
</vector>
|
111
app/src/main/res/drawable/ic_banner_foreground.xml
Normal file
@ -0,0 +1,111 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="320dp"
|
||||
android:height="180dp"
|
||||
android:viewportWidth="320"
|
||||
android:viewportHeight="180">
|
||||
<group android:scaleX="0.6666667"
|
||||
android:scaleY="0.6666667"
|
||||
android:translateX="53.333332"
|
||||
android:translateY="30">
|
||||
<group android:scaleX="0.3480663"
|
||||
android:scaleY="0.3480663"
|
||||
android:translateX="10.774034"
|
||||
android:translateY="27">
|
||||
<path
|
||||
android:pathData="M90.7,80.5L270.3,80.5A10.2,10.2 0,0 1,280.5 90.7L280.5,130.3A10.2,10.2 0,0 1,270.3 140.5L90.7,140.5A10.2,10.2 0,0 1,80.5 130.3L80.5,90.7A10.2,10.2 0,0 1,90.7 80.5z"
|
||||
android:fillColor="#74b42b"
|
||||
android:strokeColor="#00000000"/>
|
||||
<path
|
||||
android:pathData="M80.5,130.5h200v100h-200z"
|
||||
android:fillColor="#ffffff"
|
||||
android:strokeColor="#00000000"/>
|
||||
<path
|
||||
android:pathData="M90.9,150.5L270.1,150.5A10.4,10.4 0,0 1,280.5 160.9L280.5,270.1A10.4,10.4 0,0 1,270.1 280.5L90.9,280.5A10.4,10.4 0,0 1,80.5 270.1L80.5,160.9A10.4,10.4 0,0 1,90.9 150.5z"
|
||||
android:fillColor="#ffffff"
|
||||
android:strokeColor="#00000000"/>
|
||||
<path
|
||||
android:pathData="M100.5,150.5h40v40h-40z"
|
||||
android:fillColor="#b3b3b3"
|
||||
android:strokeColor="#00000000"/>
|
||||
<path
|
||||
android:pathData="M160.5,150.5h40v40h-40z"
|
||||
android:fillColor="#cccccc"
|
||||
android:strokeColor="#00000000"/>
|
||||
<path
|
||||
android:pathData="M220.5,150.5h40v40h-40z"
|
||||
android:fillColor="#e6e6e6"
|
||||
android:strokeColor="#00000000"/>
|
||||
<path
|
||||
android:pathData="M100.5,210.5h40v40h-40z"
|
||||
android:fillColor="#cccccc"
|
||||
android:strokeColor="#00000000"/>
|
||||
<path
|
||||
android:pathData="M160.5,210.5h40v40h-40z"
|
||||
android:fillColor="#e6e6e6"
|
||||
android:strokeColor="#00000000"/>
|
||||
<path
|
||||
android:pathData="M220.5,210.5h40v40h-40z"
|
||||
android:fillColor="#ebebeb"
|
||||
android:strokeColor="#00000000"/>
|
||||
<path
|
||||
android:pathData="M215.5,245.5a40,40 0,1 0,80 0a40,40 0,1 0,-80 0z"
|
||||
android:strokeWidth="2"
|
||||
android:fillColor="#ffffff"
|
||||
android:strokeColor="#cccccc"/>
|
||||
<path
|
||||
android:pathData="M228,238.17L249.07,238.17L255.5,218L261.93,238.17L283,238.17L266.21,251.67L272.87,273L255.5,259.8L238.13,273L244.79,251.67Z"
|
||||
android:fillColor="#297da6"
|
||||
android:strokeColor="#00000000"/>
|
||||
<path
|
||||
android:pathData="M223.5,70.5L237.5,70.5A3,3 0,0 1,240.5 73.5L240.5,107.5A3,3 0,0 1,237.5 110.5L223.5,110.5A3,3 0,0 1,220.5 107.5L220.5,73.5A3,3 0,0 1,223.5 70.5z"
|
||||
android:strokeWidth="2"
|
||||
android:fillColor="#cccccc"
|
||||
android:strokeColor="#ffffff"/>
|
||||
<path
|
||||
android:pathData="M123.5,70.5L137.5,70.5A3,3 0,0 1,140.5 73.5L140.5,107.5A3,3 0,0 1,137.5 110.5L123.5,110.5A3,3 0,0 1,120.5 107.5L120.5,73.5A3,3 0,0 1,123.5 70.5z"
|
||||
android:strokeWidth="2"
|
||||
android:fillColor="#cccccc"
|
||||
android:strokeColor="#ffffff"/>
|
||||
</group>
|
||||
|
||||
<group android:scaleX="0.1252506"
|
||||
android:scaleY="0.1252506"
|
||||
android:translateX="128"
|
||||
android:translateY="78.106575">
|
||||
<group android:translateY="150.89062">
|
||||
<path android:pathData="M88.8125,-0L80.4375,-0L22.296875,-88.03125L21.875,-87.96875L21.875,-0L13.4375,-0L13.4375,-102.375L21.875,-102.375L80.015625,-14.484375L80.4375,-14.5625L80.4375,-102.375L88.8125,-102.375L88.8125,-0Z"
|
||||
android:fillColor="#FFFFFF"/>
|
||||
<path android:pathData="M108.40625,-39.171875Q108.40625,-55.96875,117.609375,-66.71875Q126.828125,-77.484375,142.01562,-77.484375Q157.26562,-77.484375,166.46875,-66.71875Q175.6875,-55.96875,175.6875,-39.171875L175.6875,-36.84375Q175.6875,-19.96875,166.51562,-9.234375Q157.34375,1.484375,142.15625,1.484375Q126.828125,1.484375,117.609375,-9.234375Q108.40625,-19.96875,108.40625,-36.84375L108.40625,-39.171875ZM116.84375,-36.84375Q116.84375,-23.625,123.515625,-14.625Q130.20312,-5.625,142.15625,-5.625Q153.89062,-5.625,160.60938,-14.625Q167.32812,-23.625,167.32812,-36.84375L167.32812,-39.171875Q167.32812,-52.171875,160.57812,-61.234375Q153.82812,-70.3125,142.01562,-70.3125Q130.20312,-70.3125,123.515625,-61.234375Q116.84375,-52.171875,116.84375,-39.171875L116.84375,-36.84375Z"
|
||||
android:fillColor="#FFFFFF"/>
|
||||
<path android:pathData="M253.57812,-47.953125L203.79688,-47.953125L203.79688,0L195.4375,0L195.4375,-102.375L260.75,-102.375L260.75,-95.203125L203.79688,-95.203125L203.79688,-55.203125L253.57812,-55.203125L253.57812,-47.953125Z"
|
||||
android:fillColor="#FFFFFF"/>
|
||||
<path android:pathData="M337.42188,-35.9375Q337.42188,-18.84375,329.6875,-8.671875Q321.95312,1.484375,308.39062,1.484375Q300.01562,1.484375,293.96875,-1.859375Q287.92188,-5.203125,284.20312,-11.46875L283.28125,0L276.04688,0L276.04688,-109.6875L284.48438,-109.6875L284.48438,-64.125Q288.28125,-70.53125,294.1875,-74Q300.09375,-77.484375,308.25,-77.484375Q321.95312,-77.484375,329.6875,-66.546875Q337.42188,-55.625,337.42188,-37.40625L337.42188,-35.9375ZM328.92188,-37.40625Q328.92188,-51.96875,323.29688,-61.0625Q317.67188,-70.171875,306.625,-70.171875Q297.84375,-70.171875,292.45312,-65.8125Q287.07812,-61.453125,284.48438,-54.640625L284.48438,-20.25Q287.29688,-13.640625,292.875,-9.734375Q298.46875,-5.84375,306.76562,-5.84375Q317.8125,-5.84375,323.35938,-14Q328.92188,-22.15625,328.92188,-35.9375L328.92188,-37.40625Z"
|
||||
android:fillColor="#FFFFFF"/>
|
||||
<path android:pathData="M451.09375,-49.578125L401.79688,-49.578125L401.79688,-7.109375L458.26562,-7.109375L458.26562,0L393.4375,0L393.4375,-102.375L457.90625,-102.375L457.90625,-95.203125L401.79688,-95.203125L401.79688,-56.75L451.09375,-56.75L451.09375,-49.578125Z"
|
||||
android:fillColor="#FFFFFF"/>
|
||||
<path android:pathData="M494.76562,-19.0625L497.23438,-10.125L497.65625,-10.125L500.32812,-19.0625L521,-76.078125L529.71875,-76.078125L500.8125,0L494.0625,0L465.09375,-76.078125L473.8125,-76.078125L494.76562,-19.0625Z"
|
||||
android:fillColor="#FFFFFF"/>
|
||||
<path android:pathData="M571.65625,1.484375Q557.3906,1.484375,547.9219,-9.0625Q538.46875,-19.625,538.46875,-35.796875L538.46875,-39.65625Q538.46875,-55.96875,547.8594,-66.71875Q557.25,-77.484375,570.6094,-77.484375Q584.59375,-77.484375,592.6094,-68.625Q600.625,-59.765625,600.625,-45L600.625,-37.828125L546.90625,-37.828125L546.90625,-35.796875Q546.90625,-22.921875,553.71875,-14.265625Q560.5469,-5.625,571.65625,-5.625Q579.53125,-5.625,585.0781,-7.796875Q590.6406,-9.984375,594.5781,-14.0625L598.1719,-8.296875Q593.875,-3.796875,587.2969,-1.15625Q580.7344,1.484375,571.65625,1.484375ZM570.6094,-70.3125Q561.25,-70.3125,554.9219,-63.171875Q548.59375,-56.046875,547.5469,-45.28125L547.6875,-44.9375L592.2656,-44.9375L592.2656,-47.046875Q592.2656,-56.953125,586.4219,-63.625Q580.59375,-70.3125,570.6094,-70.3125Z"
|
||||
android:fillColor="#FFFFFF"/>
|
||||
<path android:pathData="M624.5625,-76.078125L625.34375,-62.796875Q629,-69.828125,635.21875,-73.65625Q641.4375,-77.484375,649.9531,-77.484375Q662.3281,-77.484375,668.7969,-69.921875Q675.2656,-62.375,675.2656,-46.34375L675.2656,0L666.8281,0L666.8281,-46.265625Q666.8281,-59.34375,661.9375,-64.75Q657.0469,-70.171875,648.0469,-70.171875Q639.1875,-70.171875,633.59375,-65.5Q628.0156,-60.828125,625.5469,-53.09375L625.5469,0L617.1094,0L617.1094,-76.078125L624.5625,-76.078125Z"
|
||||
android:fillColor="#FFFFFF"/>
|
||||
<path android:pathData="M710.3281,-95.5625L710.3281,-76.078125L727.0625,-76.078125L727.0625,-69.1875L710.3281,-69.1875L710.3281,-19.625Q710.3281,-12.171875,713.03125,-9.03125Q715.75,-5.90625,720.25,-5.90625Q722.28125,-5.90625,724.21875,-6.078125Q726.15625,-6.265625,728.6875,-6.6875L729.9531,-0.421875Q727.84375,0.5,724.8125,0.984375Q721.7969,1.484375,718.7656,1.484375Q710.75,1.484375,706.28125,-3.578125Q701.8281,-8.65625,701.8281,-19.625L701.8281,-69.1875L688.6719,-69.1875L688.6719,-76.078125L701.8281,-76.078125L701.8281,-95.5625L710.3281,-95.5625Z"
|
||||
android:fillColor="#FFFFFF"/>
|
||||
<path android:pathData="M840,-25.109375Q840,-33.46875,833.7344,-38.78125Q827.4844,-44.09375,811.9531,-48.171875Q795.1406,-52.390625,786.4844,-59.140625Q777.84375,-65.890625,777.84375,-77.34375Q777.84375,-89.09375,787.5156,-96.46875Q797.1875,-103.859375,812.375,-103.859375Q828.1875,-103.859375,837.8906,-95.0625Q847.59375,-86.28125,847.3125,-73.625L847.1094,-73.203125L839.375,-73.203125Q839.375,-83.46875,832.09375,-90.078125Q824.8125,-96.6875,812.375,-96.6875Q800.0625,-96.6875,793.1406,-91.203125Q786.21875,-85.71875,786.21875,-77.5625Q786.21875,-69.828125,792.6094,-64.65625Q799.0156,-59.484375,814.6875,-55.546875Q831.21875,-51.328125,839.8281,-44.15625Q848.4375,-36.984375,848.4375,-25.25Q848.4375,-13.015625,838.4219,-5.765625Q828.40625,1.484375,812.8594,1.484375Q797.53125,1.484375,786.1094,-6.21875Q774.6875,-13.921875,775.03125,-28.6875L775.1719,-29.109375L782.90625,-29.109375Q782.90625,-17.15625,791.8281,-11.390625Q800.7656,-5.625,812.8594,-5.625Q825.03125,-5.625,832.5156,-10.96875Q840,-16.3125,840,-25.109375Z"
|
||||
android:fillColor="#FFFFFF"/>
|
||||
<path android:pathData="M893.3125,-5.625Q901.6719,-5.625,908.0625,-10.40625Q914.46875,-15.1875,914.46875,-23.703125L921.9219,-23.703125L922.0625,-23.28125Q922.4219,-12.734375,913.625,-5.625Q904.84375,1.484375,893.3125,1.484375Q877.7656,1.484375,869.2969,-9.171875Q860.8281,-19.828125,860.8281,-36.5625L860.8281,-39.515625Q860.8281,-56.109375,869.3281,-66.796875Q877.84375,-77.484375,893.2344,-77.484375Q905.75,-77.484375,914.0781,-70.09375Q922.4219,-62.71875,922.1406,-50.703125L922,-50.28125L914.46875,-50.28125Q914.46875,-59.421875,908.3125,-64.859375Q902.1719,-70.3125,893.2344,-70.3125Q881,-70.3125,875.125,-61.5625Q869.2656,-52.8125,869.2656,-39.515625L869.2656,-36.5625Q869.2656,-23.0625,875.09375,-14.34375Q880.9375,-5.625,893.3125,-5.625Z"
|
||||
android:fillColor="#FFFFFF"/>
|
||||
<path android:pathData="M974.125,-68.84375L967.875,-69.265625Q959.9219,-69.265625,954.8281,-64.796875Q949.7344,-60.328125,947.5469,-52.53125L947.5469,0L939.1094,0L939.1094,-76.078125L946.5,-76.078125L947.5469,-63.421875L947.5469,-62.578125Q950.8594,-69.609375,956.40625,-73.546875Q961.96875,-77.484375,969.625,-77.484375Q971.25,-77.484375,972.75,-77.234375Q974.2656,-77,975.25,-76.71875L974.125,-68.84375Z"
|
||||
android:fillColor="#FFFFFF"/>
|
||||
<path android:pathData="M1036.2812,0Q1035.4375,-3.875,1035.0781,-6.6875Q1034.7344,-9.5,1034.7344,-12.375Q1030.5156,-6.40625,1023.4844,-2.453125Q1016.4531,1.484375,1007.65625,1.484375Q996.5469,1.484375,990.3906,-4.421875Q984.25,-10.34375,984.25,-20.25Q984.25,-30.796875,993.34375,-37.125Q1002.4531,-43.453125,1017.9219,-43.453125L1034.7344,-43.453125L1034.7344,-52.875Q1034.7344,-61.03125,1029.4844,-65.671875Q1024.25,-70.3125,1014.8281,-70.3125Q1006.0469,-70.3125,1000.2344,-65.875Q994.4375,-61.453125,994.4375,-55.0625L986.7031,-55.125L986.5625,-55.546875Q986.1406,-64.0625,994.3281,-70.765625Q1002.53125,-77.484375,1015.1875,-77.484375Q1027.7656,-77.484375,1035.4219,-71.078125Q1043.0938,-64.6875,1043.0938,-52.734375L1043.0938,-15.328125Q1043.0938,-11.328125,1043.5469,-7.53125Q1044.0156,-3.734375,1045.0625,0L1036.2812,0ZM1008.6406,-5.984375Q1017.71875,-5.984375,1024.6719,-10.234375Q1031.6406,-14.484375,1034.7344,-21.09375L1034.7344,-36.984375L1017.78125,-36.984375Q1006.3281,-36.984375,999.46875,-32.09375Q992.6094,-27.21875,992.6094,-19.96875Q992.6094,-13.78125,996.8594,-9.875Q1001.125,-5.984375,1008.6406,-5.984375Z"
|
||||
android:fillColor="#FFFFFF"/>
|
||||
<path android:pathData="M1126.3594,-35.9375Q1126.3594,-18.84375,1118.625,-8.671875Q1110.8906,1.484375,1097.3125,1.484375Q1089.2969,1.484375,1083.2812,-1.546875Q1077.2812,-4.578125,1073.4844,-10.203125L1073.4844,29.25L1065.0469,29.25L1065.0469,-76.078125L1072.1406,-76.078125L1073.2031,-64.265625Q1077,-70.59375,1083,-74.03125Q1089.0156,-77.484375,1097.1719,-77.484375Q1110.8906,-77.484375,1118.625,-66.546875Q1126.3594,-55.625,1126.3594,-37.40625L1126.3594,-35.9375ZM1117.9219,-37.40625Q1117.9219,-51.890625,1112.1562,-61.03125Q1106.3906,-70.171875,1095.2812,-70.171875Q1086.7656,-70.171875,1081.4531,-66.125Q1076.1562,-62.09375,1073.4844,-55.625L1073.4844,-19.0625Q1076.3594,-12.796875,1081.8125,-9.203125Q1087.2656,-5.625,1095.4219,-5.625Q1106.4531,-5.625,1112.1875,-13.921875Q1117.9219,-22.21875,1117.9219,-35.9375L1117.9219,-37.40625Z"
|
||||
android:fillColor="#FFFFFF"/>
|
||||
<path android:pathData="M1173.6562,1.484375Q1159.3906,1.484375,1149.9219,-9.0625Q1140.4688,-19.625,1140.4688,-35.796875L1140.4688,-39.65625Q1140.4688,-55.96875,1149.8594,-66.71875Q1159.25,-77.484375,1172.6094,-77.484375Q1186.5938,-77.484375,1194.6094,-68.625Q1202.625,-59.765625,1202.625,-45L1202.625,-37.828125L1148.9062,-37.828125L1148.9062,-35.796875Q1148.9062,-22.921875,1155.7188,-14.265625Q1162.5469,-5.625,1173.6562,-5.625Q1181.5312,-5.625,1187.0781,-7.796875Q1192.6406,-9.984375,1196.5781,-14.0625L1200.1719,-8.296875Q1195.875,-3.796875,1189.2969,-1.15625Q1182.7344,1.484375,1173.6562,1.484375ZM1172.6094,-70.3125Q1163.25,-70.3125,1156.9219,-63.171875Q1150.5938,-56.046875,1149.5469,-45.28125L1149.6875,-44.9375L1194.2656,-44.9375L1194.2656,-47.046875Q1194.2656,-56.953125,1188.4219,-63.625Q1182.5938,-70.3125,1172.6094,-70.3125Z"
|
||||
android:fillColor="#FFFFFF"/>
|
||||
<path android:pathData="M1254.125,-68.84375L1247.875,-69.265625Q1239.9219,-69.265625,1234.8281,-64.796875Q1229.7344,-60.328125,1227.5469,-52.53125L1227.5469,0L1219.1094,0L1219.1094,-76.078125L1226.5,-76.078125L1227.5469,-63.421875L1227.5469,-62.578125Q1230.8594,-69.609375,1236.4062,-73.546875Q1241.9688,-77.484375,1249.625,-77.484375Q1251.25,-77.484375,1252.75,-77.234375Q1254.2656,-77,1255.25,-76.71875L1254.125,-68.84375Z"
|
||||
android:fillColor="#FFFFFF"/>
|
||||
</group>
|
||||
</group>
|
||||
</group>
|
||||
</vector>
|
63
app/src/main/res/drawable/ic_channel_foreground.xml
Normal file
@ -0,0 +1,63 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="120dp"
|
||||
android:height="120dp"
|
||||
android:viewportWidth="120"
|
||||
android:viewportHeight="120">
|
||||
<group android:scaleX="0.078457944"
|
||||
android:scaleY="0.078457944"
|
||||
android:translateX="34.815"
|
||||
android:translateY="34.815">
|
||||
<path
|
||||
android:pathData="M0.5,0.5h640v640h-640z"
|
||||
android:fillColor="#ffffff"
|
||||
android:strokeColor="#00000000"/>
|
||||
<path
|
||||
android:pathData="M0.5,120.5h640v410h-640z"
|
||||
android:fillColor="#297da6"
|
||||
android:strokeColor="#00000000"/>
|
||||
<path
|
||||
android:pathData="M6.5,40.5L634.5,40.5A6,6 0,0 1,640.5 46.5L640.5,134.5A6,6 0,0 1,634.5 140.5L6.5,140.5A6,6 0,0 1,0.5 134.5L0.5,46.5A6,6 0,0 1,6.5 40.5z"
|
||||
android:fillColor="#74b42b"
|
||||
android:strokeColor="#00000000"/>
|
||||
<path
|
||||
android:pathData="M519.5,0.5L561.5,0.5A9,9 0,0 1,570.5 9.5L570.5,101.5A9,9 0,0 1,561.5 110.5L519.5,110.5A9,9 0,0 1,510.5 101.5L510.5,9.5A9,9 0,0 1,519.5 0.5z"
|
||||
android:fillColor="#ffffff"
|
||||
android:strokeColor="#00000000"/>
|
||||
<path
|
||||
android:pathData="M399.5,0.5L441.5,0.5A9,9 0,0 1,450.5 9.5L450.5,101.5A9,9 0,0 1,441.5 110.5L399.5,110.5A9,9 0,0 1,390.5 101.5L390.5,9.5A9,9 0,0 1,399.5 0.5z"
|
||||
android:fillColor="#ffffff"
|
||||
android:strokeColor="#00000000"/>
|
||||
<path
|
||||
android:pathData="M199.5,0.5L241.5,0.5A9,9 0,0 1,250.5 9.5L250.5,101.5A9,9 0,0 1,241.5 110.5L199.5,110.5A9,9 0,0 1,190.5 101.5L190.5,9.5A9,9 0,0 1,199.5 0.5z"
|
||||
android:fillColor="#ffffff"
|
||||
android:strokeColor="#00000000"/>
|
||||
<path
|
||||
android:pathData="M79.5,0.5L121.5,0.5A9,9 0,0 1,130.5 9.5L130.5,101.5A9,9 0,0 1,121.5 110.5L79.5,110.5A9,9 0,0 1,70.5 101.5L70.5,9.5A9,9 0,0 1,79.5 0.5z"
|
||||
android:fillColor="#ffffff"
|
||||
android:strokeColor="#00000000"/>
|
||||
<path
|
||||
android:pathData="M526.5,10.5L554.5,10.5A6,6 0,0 1,560.5 16.5L560.5,94.5A6,6 0,0 1,554.5 100.5L526.5,100.5A6,6 0,0 1,520.5 94.5L520.5,16.5A6,6 0,0 1,526.5 10.5z"
|
||||
android:fillColor="#42a3d2"
|
||||
android:strokeColor="#00000000"/>
|
||||
<path
|
||||
android:pathData="M406.5,10.5L434.5,10.5A6,6 0,0 1,440.5 16.5L440.5,94.5A6,6 0,0 1,434.5 100.5L406.5,100.5A6,6 0,0 1,400.5 94.5L400.5,16.5A6,6 0,0 1,406.5 10.5z"
|
||||
android:fillColor="#42a3d2"
|
||||
android:strokeColor="#00000000"/>
|
||||
<path
|
||||
android:pathData="M86.5,10.5L114.5,10.5A6,6 0,0 1,120.5 16.5L120.5,94.5A6,6 0,0 1,114.5 100.5L86.5,100.5A6,6 0,0 1,80.5 94.5L80.5,16.5A6,6 0,0 1,86.5 10.5z"
|
||||
android:fillColor="#42a3d2"
|
||||
android:strokeColor="#00000000"/>
|
||||
<path
|
||||
android:pathData="M206.5,10.5L234.5,10.5A6,6 0,0 1,240.5 16.5L240.5,94.5A6,6 0,0 1,234.5 100.5L206.5,100.5A6,6 0,0 1,200.5 94.5L200.5,16.5A6,6 0,0 1,206.5 10.5z"
|
||||
android:fillColor="#42a3d2"
|
||||
android:strokeColor="#00000000"/>
|
||||
<path
|
||||
android:pathData="M9.5,490.5L631.5,490.5A9,9 0,0 1,640.5 499.5L640.5,631.5A9,9 0,0 1,631.5 640.5L9.5,640.5A9,9 0,0 1,0.5 631.5L0.5,499.5A9,9 0,0 1,9.5 490.5z"
|
||||
android:fillColor="#297da6"
|
||||
android:strokeColor="#00000000"/>
|
||||
<path
|
||||
android:pathData="M155.5,295.5L281.94,295.5L320.5,174.5L359.06,295.5L485.5,295.5L384.76,376.53L424.71,504.5L320.5,425.3L216.29,504.5L256.24,376.53Z"
|
||||
android:fillColor="#ffffff"
|
||||
android:strokeColor="#00000000"/>
|
||||
</group>
|
||||
</vector>
|
9
app/src/main/res/drawable/ic_content_paste.xml
Normal file
@ -0,0 +1,9 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M19,2h-4.18C14.4,0.84 13.3,0 12,0c-1.3,0 -2.4,0.84 -2.82,2L5,2c-1.1,0 -2,0.9 -2,2v16c0,1.1 0.9,2 2,2h14c1.1,0 2,-0.9 2,-2L21,4c0,-1.1 -0.9,-2 -2,-2zM12,2c0.55,0 1,0.45 1,1s-0.45,1 -1,1 -1,-0.45 -1,-1 0.45,-1 1,-1zM19,20L5,20L5,4h2v3h10L17,4h2v16z"/>
|
||||
</vector>
|
9
app/src/main/res/drawable/ic_event_available.xml
Normal file
@ -0,0 +1,9 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:pathData="M16.53,11.06L15.47,10l-4.88,4.88 -2.12,-2.12 -1.06,1.06L10.59,17l5.94,-5.94zM19,3h-1L18,1h-2v2L8,3L8,1L6,1v2L5,3c-1.11,0 -1.99,0.9 -1.99,2L3,19c0,1.1 0.89,2 2,2h14c1.1,0 2,-0.9 2,-2L21,5c0,-1.1 -0.9,-2 -2,-2zM19,19L5,19L5,8h14v11z"
|
||||
android:fillColor="#000000"/>
|
||||
</vector>
|
9
app/src/main/res/drawable/ic_help.xml
Normal file
@ -0,0 +1,9 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:pathData="M12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zM13,19h-2v-2h2v2zM15.07,11.25l-0.9,0.92C13.45,12.9 13,13.5 13,15h-2v-0.5c0,-1.1 0.45,-2.1 1.17,-2.83l1.24,-1.26c0.37,-0.36 0.59,-0.86 0.59,-1.41 0,-1.1 -0.9,-2 -2,-2s-2,0.9 -2,2L8,9c0,-2.21 1.79,-4 4,-4s4,1.79 4,4c0,0.88 -0.36,1.68 -0.93,2.25z"
|
||||
android:fillColor="#000000"/>
|
||||
</vector>
|
@ -1,58 +0,0 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="642dp"
|
||||
android:height="642dp"
|
||||
android:viewportWidth="642"
|
||||
android:viewportHeight="642">
|
||||
<path
|
||||
android:pathData="M0.5,0.5h640v640h-640z"
|
||||
android:fillColor="#ffffff"
|
||||
android:strokeColor="#00000000"/>
|
||||
<path
|
||||
android:pathData="M0.5,120.5h640v410h-640z"
|
||||
android:fillColor="#297da6"
|
||||
android:strokeColor="#00000000"/>
|
||||
<path
|
||||
android:pathData="M6.5,40.5L634.5,40.5A6,6 0,0 1,640.5 46.5L640.5,134.5A6,6 0,0 1,634.5 140.5L6.5,140.5A6,6 0,0 1,0.5 134.5L0.5,46.5A6,6 0,0 1,6.5 40.5z"
|
||||
android:fillColor="#74b42b"
|
||||
android:strokeColor="#00000000"/>
|
||||
<path
|
||||
android:pathData="M519.5,0.5L561.5,0.5A9,9 0,0 1,570.5 9.5L570.5,101.5A9,9 0,0 1,561.5 110.5L519.5,110.5A9,9 0,0 1,510.5 101.5L510.5,9.5A9,9 0,0 1,519.5 0.5z"
|
||||
android:fillColor="#ffffff"
|
||||
android:strokeColor="#00000000"/>
|
||||
<path
|
||||
android:pathData="M399.5,0.5L441.5,0.5A9,9 0,0 1,450.5 9.5L450.5,101.5A9,9 0,0 1,441.5 110.5L399.5,110.5A9,9 0,0 1,390.5 101.5L390.5,9.5A9,9 0,0 1,399.5 0.5z"
|
||||
android:fillColor="#ffffff"
|
||||
android:strokeColor="#00000000"/>
|
||||
<path
|
||||
android:pathData="M199.5,0.5L241.5,0.5A9,9 0,0 1,250.5 9.5L250.5,101.5A9,9 0,0 1,241.5 110.5L199.5,110.5A9,9 0,0 1,190.5 101.5L190.5,9.5A9,9 0,0 1,199.5 0.5z"
|
||||
android:fillColor="#ffffff"
|
||||
android:strokeColor="#00000000"/>
|
||||
<path
|
||||
android:pathData="M79.5,0.5L121.5,0.5A9,9 0,0 1,130.5 9.5L130.5,101.5A9,9 0,0 1,121.5 110.5L79.5,110.5A9,9 0,0 1,70.5 101.5L70.5,9.5A9,9 0,0 1,79.5 0.5z"
|
||||
android:fillColor="#ffffff"
|
||||
android:strokeColor="#00000000"/>
|
||||
<path
|
||||
android:pathData="M526.5,10.5L554.5,10.5A6,6 0,0 1,560.5 16.5L560.5,94.5A6,6 0,0 1,554.5 100.5L526.5,100.5A6,6 0,0 1,520.5 94.5L520.5,16.5A6,6 0,0 1,526.5 10.5z"
|
||||
android:fillColor="#42a3d2"
|
||||
android:strokeColor="#00000000"/>
|
||||
<path
|
||||
android:pathData="M406.5,10.5L434.5,10.5A6,6 0,0 1,440.5 16.5L440.5,94.5A6,6 0,0 1,434.5 100.5L406.5,100.5A6,6 0,0 1,400.5 94.5L400.5,16.5A6,6 0,0 1,406.5 10.5z"
|
||||
android:fillColor="#42a3d2"
|
||||
android:strokeColor="#00000000"/>
|
||||
<path
|
||||
android:pathData="M86.5,10.5L114.5,10.5A6,6 0,0 1,120.5 16.5L120.5,94.5A6,6 0,0 1,114.5 100.5L86.5,100.5A6,6 0,0 1,80.5 94.5L80.5,16.5A6,6 0,0 1,86.5 10.5z"
|
||||
android:fillColor="#42a3d2"
|
||||
android:strokeColor="#00000000"/>
|
||||
<path
|
||||
android:pathData="M206.5,10.5L234.5,10.5A6,6 0,0 1,240.5 16.5L240.5,94.5A6,6 0,0 1,234.5 100.5L206.5,100.5A6,6 0,0 1,200.5 94.5L200.5,16.5A6,6 0,0 1,206.5 10.5z"
|
||||
android:fillColor="#42a3d2"
|
||||
android:strokeColor="#00000000"/>
|
||||
<path
|
||||
android:pathData="M9.5,490.5L631.5,490.5A9,9 0,0 1,640.5 499.5L640.5,631.5A9,9 0,0 1,631.5 640.5L9.5,640.5A9,9 0,0 1,0.5 631.5L0.5,499.5A9,9 0,0 1,9.5 490.5z"
|
||||
android:fillColor="#297da6"
|
||||
android:strokeColor="#00000000"/>
|
||||
<path
|
||||
android:pathData="M155.5,295.5L281.94,295.5L320.5,174.5L359.06,295.5L485.5,295.5L384.76,376.53L424.71,504.5L320.5,425.3L216.29,504.5L256.24,376.53Z"
|
||||
android:fillColor="#ffffff"
|
||||
android:strokeColor="#00000000"/>
|
||||
</vector>
|
9
app/src/main/res/drawable/ic_info.xml
Normal file
@ -0,0 +1,9 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:pathData="M12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zM13,17h-2v-6h2v6zM13,9h-2L11,7h2v2z"
|
||||
android:fillColor="#000000"/>
|
||||
</vector>
|
@ -1,61 +1,66 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="108dp"
|
||||
android:height="108dp"
|
||||
android:viewportWidth="1605"
|
||||
android:viewportHeight="1605">
|
||||
<group android:translateX="481.5"
|
||||
android:translateY="481.5">
|
||||
android:viewportWidth="108"
|
||||
android:viewportHeight="108">
|
||||
<group android:scaleX="0.21480663"
|
||||
android:scaleY="0.21480663"
|
||||
android:translateX="15.227404"
|
||||
android:translateY="15.12">
|
||||
<path
|
||||
android:pathData="M0.5,0.5h640v640h-640z"
|
||||
android:fillColor="#ffffff"
|
||||
android:strokeColor="#00000000"/>
|
||||
<path
|
||||
android:pathData="M0.5,120.5h640v410h-640z"
|
||||
android:fillColor="#297da6"
|
||||
android:strokeColor="#00000000"/>
|
||||
<path
|
||||
android:pathData="M6.5,40.5L634.5,40.5A6,6 0,0 1,640.5 46.5L640.5,134.5A6,6 0,0 1,634.5 140.5L6.5,140.5A6,6 0,0 1,0.5 134.5L0.5,46.5A6,6 0,0 1,6.5 40.5z"
|
||||
android:pathData="M90.7,80.5L270.3,80.5A10.2,10.2 0,0 1,280.5 90.7L280.5,130.3A10.2,10.2 0,0 1,270.3 140.5L90.7,140.5A10.2,10.2 0,0 1,80.5 130.3L80.5,90.7A10.2,10.2 0,0 1,90.7 80.5z"
|
||||
android:fillColor="#74b42b"
|
||||
android:strokeColor="#00000000"/>
|
||||
<path
|
||||
android:pathData="M519.5,0.5L561.5,0.5A9,9 0,0 1,570.5 9.5L570.5,101.5A9,9 0,0 1,561.5 110.5L519.5,110.5A9,9 0,0 1,510.5 101.5L510.5,9.5A9,9 0,0 1,519.5 0.5z"
|
||||
android:pathData="M80.5,130.5h200v100h-200z"
|
||||
android:fillColor="#ffffff"
|
||||
android:strokeColor="#00000000"/>
|
||||
<path
|
||||
android:pathData="M399.5,0.5L441.5,0.5A9,9 0,0 1,450.5 9.5L450.5,101.5A9,9 0,0 1,441.5 110.5L399.5,110.5A9,9 0,0 1,390.5 101.5L390.5,9.5A9,9 0,0 1,399.5 0.5z"
|
||||
android:pathData="M90.9,150.5L270.1,150.5A10.4,10.4 0,0 1,280.5 160.9L280.5,270.1A10.4,10.4 0,0 1,270.1 280.5L90.9,280.5A10.4,10.4 0,0 1,80.5 270.1L80.5,160.9A10.4,10.4 0,0 1,90.9 150.5z"
|
||||
android:fillColor="#ffffff"
|
||||
android:strokeColor="#00000000"/>
|
||||
<path
|
||||
android:pathData="M199.5,0.5L241.5,0.5A9,9 0,0 1,250.5 9.5L250.5,101.5A9,9 0,0 1,241.5 110.5L199.5,110.5A9,9 0,0 1,190.5 101.5L190.5,9.5A9,9 0,0 1,199.5 0.5z"
|
||||
android:pathData="M100.5,150.5h40v40h-40z"
|
||||
android:fillColor="#b3b3b3"
|
||||
android:strokeColor="#00000000"/>
|
||||
<path
|
||||
android:pathData="M160.5,150.5h40v40h-40z"
|
||||
android:fillColor="#cccccc"
|
||||
android:strokeColor="#00000000"/>
|
||||
<path
|
||||
android:pathData="M220.5,150.5h40v40h-40z"
|
||||
android:fillColor="#e6e6e6"
|
||||
android:strokeColor="#00000000"/>
|
||||
<path
|
||||
android:pathData="M100.5,210.5h40v40h-40z"
|
||||
android:fillColor="#cccccc"
|
||||
android:strokeColor="#00000000"/>
|
||||
<path
|
||||
android:pathData="M160.5,210.5h40v40h-40z"
|
||||
android:fillColor="#e6e6e6"
|
||||
android:strokeColor="#00000000"/>
|
||||
<path
|
||||
android:pathData="M220.5,210.5h40v40h-40z"
|
||||
android:fillColor="#ebebeb"
|
||||
android:strokeColor="#00000000"/>
|
||||
<path
|
||||
android:pathData="M215.5,245.5a40,40 0,1 0,80 0a40,40 0,1 0,-80 0z"
|
||||
android:strokeWidth="2"
|
||||
android:fillColor="#ffffff"
|
||||
android:strokeColor="#00000000"/>
|
||||
android:strokeColor="#cccccc"/>
|
||||
<path
|
||||
android:pathData="M79.5,0.5L121.5,0.5A9,9 0,0 1,130.5 9.5L130.5,101.5A9,9 0,0 1,121.5 110.5L79.5,110.5A9,9 0,0 1,70.5 101.5L70.5,9.5A9,9 0,0 1,79.5 0.5z"
|
||||
android:fillColor="#ffffff"
|
||||
android:strokeColor="#00000000"/>
|
||||
<path
|
||||
android:pathData="M526.5,10.5L554.5,10.5A6,6 0,0 1,560.5 16.5L560.5,94.5A6,6 0,0 1,554.5 100.5L526.5,100.5A6,6 0,0 1,520.5 94.5L520.5,16.5A6,6 0,0 1,526.5 10.5z"
|
||||
android:fillColor="#42a3d2"
|
||||
android:strokeColor="#00000000"/>
|
||||
<path
|
||||
android:pathData="M406.5,10.5L434.5,10.5A6,6 0,0 1,440.5 16.5L440.5,94.5A6,6 0,0 1,434.5 100.5L406.5,100.5A6,6 0,0 1,400.5 94.5L400.5,16.5A6,6 0,0 1,406.5 10.5z"
|
||||
android:fillColor="#42a3d2"
|
||||
android:strokeColor="#00000000"/>
|
||||
<path
|
||||
android:pathData="M86.5,10.5L114.5,10.5A6,6 0,0 1,120.5 16.5L120.5,94.5A6,6 0,0 1,114.5 100.5L86.5,100.5A6,6 0,0 1,80.5 94.5L80.5,16.5A6,6 0,0 1,86.5 10.5z"
|
||||
android:fillColor="#42a3d2"
|
||||
android:strokeColor="#00000000"/>
|
||||
<path
|
||||
android:pathData="M206.5,10.5L234.5,10.5A6,6 0,0 1,240.5 16.5L240.5,94.5A6,6 0,0 1,234.5 100.5L206.5,100.5A6,6 0,0 1,200.5 94.5L200.5,16.5A6,6 0,0 1,206.5 10.5z"
|
||||
android:fillColor="#42a3d2"
|
||||
android:strokeColor="#00000000"/>
|
||||
<path
|
||||
android:pathData="M9.5,490.5L631.5,490.5A9,9 0,0 1,640.5 499.5L640.5,631.5A9,9 0,0 1,631.5 640.5L9.5,640.5A9,9 0,0 1,0.5 631.5L0.5,499.5A9,9 0,0 1,9.5 490.5z"
|
||||
android:pathData="M228,238.17L249.07,238.17L255.5,218L261.93,238.17L283,238.17L266.21,251.67L272.87,273L255.5,259.8L238.13,273L244.79,251.67Z"
|
||||
android:fillColor="#297da6"
|
||||
android:strokeColor="#00000000"/>
|
||||
<path
|
||||
android:pathData="M155.5,295.5L281.94,295.5L320.5,174.5L359.06,295.5L485.5,295.5L384.76,376.53L424.71,504.5L320.5,425.3L216.29,504.5L256.24,376.53Z"
|
||||
android:fillColor="#ffffff"
|
||||
android:strokeColor="#00000000"/>
|
||||
android:pathData="M223.5,70.5L237.5,70.5A3,3 0,0 1,240.5 73.5L240.5,107.5A3,3 0,0 1,237.5 110.5L223.5,110.5A3,3 0,0 1,220.5 107.5L220.5,73.5A3,3 0,0 1,223.5 70.5z"
|
||||
android:strokeWidth="2"
|
||||
android:fillColor="#cccccc"
|
||||
android:strokeColor="#ffffff"/>
|
||||
<path
|
||||
android:pathData="M123.5,70.5L137.5,70.5A3,3 0,0 1,140.5 73.5L140.5,107.5A3,3 0,0 1,137.5 110.5L123.5,110.5A3,3 0,0 1,120.5 107.5L120.5,73.5A3,3 0,0 1,123.5 70.5z"
|
||||
android:strokeWidth="2"
|
||||
android:fillColor="#cccccc"
|
||||
android:strokeColor="#ffffff"/>
|
||||
</group>
|
||||
</vector>
|
||||
|
9
app/src/main/res/drawable/ic_settings.xml
Normal file
@ -0,0 +1,9 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:pathData="M19.14,12.94c0.04,-0.3 0.06,-0.61 0.06,-0.94c0,-0.32 -0.02,-0.64 -0.07,-0.94l2.03,-1.58c0.18,-0.14 0.23,-0.41 0.12,-0.61l-1.92,-3.32c-0.12,-0.22 -0.37,-0.29 -0.59,-0.22l-2.39,0.96c-0.5,-0.38 -1.03,-0.7 -1.62,-0.94L14.4,2.81c-0.04,-0.24 -0.24,-0.41 -0.48,-0.41h-3.84c-0.24,0 -0.43,0.17 -0.47,0.41L9.25,5.35C8.66,5.59 8.12,5.92 7.63,6.29L5.24,5.33c-0.22,-0.08 -0.47,0 -0.59,0.22L2.74,8.87C2.62,9.08 2.66,9.34 2.86,9.48l2.03,1.58C4.84,11.36 4.8,11.69 4.8,12s0.02,0.64 0.07,0.94l-2.03,1.58c-0.18,0.14 -0.23,0.41 -0.12,0.61l1.92,3.32c0.12,0.22 0.37,0.29 0.59,0.22l2.39,-0.96c0.5,0.38 1.03,0.7 1.62,0.94l0.36,2.54c0.05,0.24 0.24,0.41 0.48,0.41h3.84c0.24,0 0.44,-0.17 0.47,-0.41l0.36,-2.54c0.59,-0.24 1.13,-0.56 1.62,-0.94l2.39,0.96c0.22,0.08 0.47,0 0.59,-0.22l1.92,-3.32c0.12,-0.22 0.07,-0.47 -0.12,-0.61L19.14,12.94zM12,15.6c-1.98,0 -3.6,-1.62 -3.6,-3.6s1.62,-3.6 3.6,-3.6s3.6,1.62 3.6,3.6S13.98,15.6 12,15.6z"
|
||||
android:fillColor="#000000"/>
|
||||
</vector>
|
@ -1,75 +1,15 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
tools:context=".AboutActivity">
|
||||
|
||||
<ScrollView
|
||||
|
||||
<WebView
|
||||
android:id="@+id/webview_about"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/about_heading"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="16dp"
|
||||
android:text="@string/action_about"
|
||||
android:textAppearance="@style/TextAppearance.AppCompat.Large" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/about_text"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="16dp"
|
||||
android:text="@string/about_text"
|
||||
android:textAppearance="@style/TextAppearance.AppCompat.Medium" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/open_source_heading"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="16dp"
|
||||
android:layout_marginTop="32dp"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:text="@string/open_source_heading"
|
||||
android:textAppearance="@style/TextAppearance.AppCompat.Large" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/open_source_text"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="16dp"
|
||||
android:autoLink="web"
|
||||
android:text="@string/open_source_text"
|
||||
android:textAppearance="@style/TextAppearance.AppCompat.Medium" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/changelog_heading"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="16dp"
|
||||
android:layout_marginTop="32dp"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:text="@string/changelog_heading"
|
||||
android:textAppearance="@style/TextAppearance.AppCompat.Large" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/changelog_text"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="16dp"
|
||||
android:autoLink="web"
|
||||
android:text="@string/changelog_text"
|
||||
android:textAppearance="@style/TextAppearance.AppCompat.Medium" />
|
||||
|
||||
</LinearLayout>
|
||||
</ScrollView>
|
||||
android:layout_height="match_parent" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
15
app/src/main/res/layout/activity_help.xml
Normal file
@ -0,0 +1,15 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
tools:context=".HelpActivity">
|
||||
|
||||
|
||||
<WebView
|
||||
android:id="@+id/webview_help"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
@ -1,29 +1,93 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
|
||||
<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"
|
||||
tools:context=".MainActivity">
|
||||
|
||||
<com.google.android.material.appbar.AppBarLayout
|
||||
android:id="@+id/app_bar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_height="180dp"
|
||||
android:fitsSystemWindows="true"
|
||||
android:theme="@style/AppTheme.AppBarOverlay">
|
||||
|
||||
<androidx.appcompat.widget.Toolbar
|
||||
android:id="@+id/toolbar"
|
||||
<com.google.android.material.appbar.CollapsingToolbarLayout
|
||||
android:id="@+id/layout_toolbar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="?attr/actionBarSize"
|
||||
android:background="?attr/colorPrimary"
|
||||
app:popupTheme="@style/AppTheme.PopupOverlay" />
|
||||
android:layout_height="match_parent"
|
||||
android:background="@color/colorPrimary"
|
||||
android:fitsSystemWindows="true"
|
||||
app:contentScrim="?attr/colorPrimary"
|
||||
app:expandedTitleGravity="center"
|
||||
app:layout_scrollFlags="scroll|exitUntilCollapsed"
|
||||
app:toolbarId="@+id/toolbar">
|
||||
|
||||
<!-- android:src="@drawable/ic_banner_foreground"-->
|
||||
|
||||
|
||||
<androidx.appcompat.widget.AppCompatImageView
|
||||
android:id="@+id/image_view"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:fitsSystemWindows="true"
|
||||
android:scaleType="centerCrop"
|
||||
app:layout_collapseMode="parallax" />
|
||||
|
||||
<androidx.appcompat.widget.Toolbar
|
||||
android:id="@+id/toolbar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="?attr/actionBarSize"
|
||||
app:layout_collapseMode="pin"
|
||||
app:popupTheme="@style/AppTheme.PopupOverlay"
|
||||
app:title="NoFb Event Scraper" />
|
||||
|
||||
</com.google.android.material.appbar.CollapsingToolbarLayout>
|
||||
|
||||
|
||||
</com.google.android.material.appbar.AppBarLayout>
|
||||
|
||||
<include
|
||||
layout="@layout/content_main"
|
||||
<com.google.android.material.floatingactionbutton.ExtendedFloatingActionButton
|
||||
android:id="@+id/paste_button"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginEnd="64dp"
|
||||
app:layout_anchor="@id/app_bar"
|
||||
app:layout_anchorGravity="bottom|end"
|
||||
app:icon="@drawable/ic_content_paste"
|
||||
android:text="@string/paste_button"/>
|
||||
|
||||
<include layout="@layout/content_main" />
|
||||
|
||||
<com.google.android.material.bottomappbar.BottomAppBar
|
||||
android:id="@+id/bottom_appbar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent" />
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="bottom"
|
||||
android:layout_margin="0dp"
|
||||
app:contentInsetStart="0dp">
|
||||
|
||||
|
||||
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
||||
<Button
|
||||
android:id="@+id/ok_button"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="16dp"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:layout_weight="1"
|
||||
android:padding="12dp"
|
||||
android:text="@string/add_to_calendar"
|
||||
android:textColor="#FFFFFF"
|
||||
app:cornerRadius="24dp"
|
||||
app:icon="@drawable/ic_event_available"
|
||||
app:iconGravity="textStart"
|
||||
app:iconPadding="16dp"
|
||||
app:iconTint="#FFFFFF" />
|
||||
|
||||
</com.google.android.material.bottomappbar.BottomAppBar>
|
||||
|
||||
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
||||
|
@ -1,171 +1,145 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.constraintlayout.widget.ConstraintLayout 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:layout_height="match_parent"
|
||||
android:animateLayoutChanges="false"
|
||||
app:layout_behavior="@string/appbar_scrolling_view_behavior"
|
||||
tools:context=".MainActivity"
|
||||
tools:showIn="@layout/activity_main">
|
||||
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/linearLayout4"
|
||||
android:layout_width="0dp"
|
||||
android:id="@+id/linear_layout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="16dp"
|
||||
android:layout_marginTop="64dp"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:gravity="center"
|
||||
android:layout_marginTop="32dp"
|
||||
android:layout_marginBottom="64dp"
|
||||
|
||||
android:divider="@drawable/divider"
|
||||
android:orientation="vertical"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent">
|
||||
android:showDividers="middle">
|
||||
|
||||
<Button
|
||||
android:id="@+id/paste_button"
|
||||
style="@style/Widget.AppCompat.Button"
|
||||
android:layout_width="wrap_content"
|
||||
|
||||
<com.google.android.material.textfield.TextInputLayout
|
||||
android:id="@+id/layout_uri_input"
|
||||
style="@style/Widget.MaterialComponents.TextInputLayout.FilledBox"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:text="@android:string/paste" />
|
||||
|
||||
app:endIconCheckable="false"
|
||||
app:endIconDrawable="@drawable/ic_backspace_black"
|
||||
app:errorIconDrawable="@drawable/ic_backspace_black"
|
||||
app:endIconMode="custom"
|
||||
|
||||
app:helperText="@string/add_link_helper"
|
||||
app:helperTextEnabled="true">
|
||||
|
||||
<com.google.android.material.textfield.TextInputEditText
|
||||
android:id="@+id/edit_text_uri_input"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:autoLink="web"
|
||||
android:cursorVisible="true"
|
||||
android:hint="@string/add_link_hint"
|
||||
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.TextInputEditText
|
||||
android:id="@+id/edit_text_event_name"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
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.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.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
|
||||
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/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.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>
|
||||
|
||||
<com.google.android.material.textfield.TextInputLayout
|
||||
android:id="@+id/textInputLayout"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="16dp"
|
||||
android:layout_marginTop="16dp"
|
||||
android:layout_marginEnd="16dp"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/linearLayout4">
|
||||
|
||||
<com.google.android.material.textfield.TextInputEditText
|
||||
android:id="@+id/field_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:singleLine="true" />
|
||||
</com.google.android.material.textfield.TextInputLayout>
|
||||
|
||||
<ScrollView
|
||||
android:id="@+id/scrollView"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="0dp"
|
||||
android:layout_marginStart="16dp"
|
||||
android:layout_marginTop="16dp"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:layout_marginBottom="16dp"
|
||||
app:layout_constraintBottom_toTopOf="@+id/bottomButtonLayout"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/textInputLayout">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical" >
|
||||
|
||||
<com.google.android.material.textfield.TextInputLayout
|
||||
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:singleLine="true" />
|
||||
</com.google.android.material.textfield.TextInputLayout>
|
||||
|
||||
<com.google.android.material.textfield.TextInputLayout
|
||||
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:hint="Event start"
|
||||
android:singleLine="true" />
|
||||
</com.google.android.material.textfield.TextInputLayout>
|
||||
|
||||
<com.google.android.material.textfield.TextInputLayout
|
||||
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:hint="Event end"
|
||||
android:singleLine="true" />
|
||||
</com.google.android.material.textfield.TextInputLayout>
|
||||
|
||||
<com.google.android.material.textfield.TextInputLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<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:singleLine="true" />
|
||||
</com.google.android.material.textfield.TextInputLayout>
|
||||
|
||||
<com.google.android.material.textfield.TextInputLayout
|
||||
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:singleLine="false" />
|
||||
</com.google.android.material.textfield.TextInputLayout>
|
||||
|
||||
</LinearLayout>
|
||||
</ScrollView>
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/bottomButtonLayout"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="16dp"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:layout_marginBottom="16dp"
|
||||
android:orientation="horizontal"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent">
|
||||
|
||||
<Button
|
||||
android:id="@+id/cancel_button"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:text="@android:string/cancel" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/ok_button"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:text="@android:string/ok" />
|
||||
</LinearLayout>
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
</androidx.core.widget.NestedScrollView>
|
9
app/src/main/res/layout/settings_activity.xml
Normal file
@ -0,0 +1,9 @@
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<FrameLayout
|
||||
android:id="@+id/settings"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent" />
|
||||
</LinearLayout>
|
@ -4,7 +4,17 @@
|
||||
tools:context="com.akdev.nofbeventscraper.MainActivity">
|
||||
<item
|
||||
android:id="@+id/action_about"
|
||||
android:icon="@android:drawable/ic_menu_info_details"
|
||||
android:icon="@drawable/ic_info"
|
||||
android:orderInCategory="100"
|
||||
android:title="@string/action_about" />
|
||||
<item
|
||||
android:id="@+id/action_help"
|
||||
android:icon="@drawable/ic_help"
|
||||
android:orderInCategory="100"
|
||||
android:title="@string/action_help" />
|
||||
<item
|
||||
android:id="@+id/action_settings"
|
||||
android:icon="@drawable/ic_settings"
|
||||
android:orderInCategory="100"
|
||||
android:title="@string/action_settings" />
|
||||
</menu>
|
||||
|
5
app/src/main/res/mipmap-anydpi-v26/ic_banner.xml
Normal file
@ -0,0 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<background android:drawable="@color/ic_banner_background"/>
|
||||
<foreground android:drawable="@drawable/ic_banner_foreground"/>
|
||||
</adaptive-icon>
|
5
app/src/main/res/mipmap-anydpi-v26/ic_channel.xml
Normal file
@ -0,0 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<background android:drawable="@color/ic_channel_background"/>
|
||||
<foreground android:drawable="@drawable/ic_channel_foreground"/>
|
||||
</adaptive-icon>
|
Before Width: | Height: | Size: 1.6 KiB After Width: | Height: | Size: 1.7 KiB |
Before Width: | Height: | Size: 3.3 KiB After Width: | Height: | Size: 3.5 KiB |
Before Width: | Height: | Size: 1.2 KiB After Width: | Height: | Size: 1.4 KiB |
Before Width: | Height: | Size: 2.2 KiB After Width: | Height: | Size: 2.4 KiB |
BIN
app/src/main/res/mipmap-xhdpi/ic_banner.png
Normal file
After Width: | Height: | Size: 3.3 KiB |
BIN
app/src/main/res/mipmap-xhdpi/ic_channel.png
Normal file
After Width: | Height: | Size: 1.7 KiB |
Before Width: | Height: | Size: 2.1 KiB After Width: | Height: | Size: 2.3 KiB |
Before Width: | Height: | Size: 4.6 KiB After Width: | Height: | Size: 5.0 KiB |
Before Width: | Height: | Size: 3.0 KiB After Width: | Height: | Size: 3.3 KiB |
Before Width: | Height: | Size: 7.2 KiB After Width: | Height: | Size: 7.4 KiB |
Before Width: | Height: | Size: 4.1 KiB After Width: | Height: | Size: 4.5 KiB |
Before Width: | Height: | Size: 10 KiB After Width: | Height: | Size: 11 KiB |
13
app/src/main/res/values/arrays.xml
Normal file
@ -0,0 +1,13 @@
|
||||
<resources>
|
||||
<!-- Reply Preference -->
|
||||
<string-array name="url_to_scrape">
|
||||
<item>m.facebook.com</item>
|
||||
<item>www.facebook.com</item>
|
||||
</string-array>
|
||||
|
||||
<string-array name="url_prefix">
|
||||
<item>https://m.</item>
|
||||
<item>https://www.</item>
|
||||
</string-array>
|
||||
|
||||
</resources>
|
@ -2,5 +2,5 @@
|
||||
<resources>
|
||||
<color name="colorPrimary">#297DA6</color>
|
||||
<color name="colorPrimaryDark">#23607E</color>
|
||||
<color name="colorAccent">#297DA6</color>ink
|
||||
<color name="colorAccent">#297DA6</color>
|
||||
</resources>
|
||||
|
4
app/src/main/res/values/ic_banner_background.xml
Normal file
@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<color name="ic_banner_background">#23607E</color>
|
||||
</resources>
|
4
app/src/main/res/values/ic_channel_background.xml
Normal file
@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<color name="ic_channel_background">#FFFFFF</color>
|
||||
</resources>
|
@ -1,4 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<color name="ic_launcher_background">#FFFFFF</color>
|
||||
<color name="ic_launcher_background">#23607E</color>
|
||||
</resources>
|
@ -1,15 +1,19 @@
|
||||
<resources>
|
||||
<string name="app_name">NoFb Event Scraper</string>
|
||||
<string name="action_about">About</string>
|
||||
<string name="add_link_hint">Paste facebook link to the event.</string>
|
||||
<string name="about_text">This application was developed to be used without a facebook account.
|
||||
\nTherefore it does not use the facebook API.
|
||||
Instead it opens the facebook event URI and downloads the website source code.
|
||||
This source contains the information which is used to create a calendar entry.
|
||||
</string>
|
||||
<string name="open_source_heading"> Open Source </string>
|
||||
<string name="open_source_text"> The source code for this application can be found at https://github.com/akaessens/NoFbEventScraper .</string>
|
||||
<string name="action_help">Help</string>
|
||||
<string name="action_settings">Settings</string>
|
||||
<string name="add_link_hint">Event link</string>
|
||||
<string name="add_link_helper">Paste facebook link to the event.</string>
|
||||
<string name="add_to_calendar">Add to calendar</string>
|
||||
<string name="paste_button">Paste from clipboard</string>
|
||||
|
||||
<!-- Preference Titles -->
|
||||
<string name="scraper_header">Scraper</string>
|
||||
|
||||
<string name="url_setting">Which URL to scrape</string>
|
||||
<string name="url_setting_summary">
|
||||
Using m.facebook.com is more stable and faster. Using www.facebook.com works better with multiple instance events but will eventually break when facebook disables the classic design.
|
||||
</string>
|
||||
|
||||
<string name="changelog_heading"> Changelog </string>
|
||||
<string name="changelog_text"> v0.1.0\t\tInitial release.</string>
|
||||
</resources>
|
||||
|
@ -1,8 +1,8 @@
|
||||
<resources>
|
||||
|
||||
<!-- Base application theme. -->
|
||||
<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
|
||||
<!-- Customize your theme here. -->
|
||||
<style name="AppTheme" parent="Theme.MaterialComponents.DayNight">
|
||||
<!-- Customize your theme here.-->
|
||||
<item name="colorPrimary">@color/colorPrimary</item>
|
||||
<item name="colorPrimaryDark">@color/colorPrimaryDark</item>
|
||||
<item name="colorAccent">@color/colorAccent</item>
|
||||
@ -13,8 +13,8 @@
|
||||
<item name="windowNoTitle">true</item>
|
||||
</style>
|
||||
|
||||
<style name="AppTheme.AppBarOverlay" parent="ThemeOverlay.AppCompat.Dark.ActionBar" />
|
||||
<style name="AppTheme.AppBarOverlay" parent="ThemeOverlay.MaterialComponents.Dark.ActionBar" />
|
||||
|
||||
<style name="AppTheme.PopupOverlay" parent="ThemeOverlay.AppCompat.Light" />
|
||||
<style name="AppTheme.PopupOverlay" parent="ThemeOverlay.MaterialComponents.Light" />
|
||||
|
||||
</resources>
|
||||
|
21
app/src/main/res/xml/root_preferences.xml
Normal file
@ -0,0 +1,21 @@
|
||||
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||
|
||||
<PreferenceCategory app:title="@string/scraper_header">
|
||||
|
||||
|
||||
<ListPreference
|
||||
app:defaultValue="https://m."
|
||||
app:entries="@array/url_to_scrape"
|
||||
app:entryValues="@array/url_prefix"
|
||||
app:key="url_preference"
|
||||
app:title="@string/url_setting"
|
||||
android:summary="@string/url_setting_summary"/>
|
||||
|
||||
|
||||
|
||||
</PreferenceCategory>
|
||||
|
||||
|
||||
|
||||
</PreferenceScreen>
|
@ -8,7 +8,7 @@ buildscript {
|
||||
|
||||
}
|
||||
dependencies {
|
||||
classpath 'com.android.tools.build:gradle:3.6.1'
|
||||
classpath 'com.android.tools.build:gradle:4.0.0'
|
||||
|
||||
// NOTE: Do not place your application dependencies here; they belong
|
||||
// in the individual module build.gradle files
|
||||
|
3
fastlane/metadata/android/en-US/changelogs/2.txt
Normal file
@ -0,0 +1,3 @@
|
||||
Added help and reports section.
|
||||
Fix for some locations not scraped correctly.
|
||||
Resolve fb-internal links.
|
3
fastlane/metadata/android/en-US/changelogs/3.txt
Normal file
@ -0,0 +1,3 @@
|
||||
Fix for timezone calculation.
|
||||
Material design Interface, will be improved further.
|
||||
Display the event picture in the toolbar.
|
3
fastlane/metadata/android/en-US/changelogs/4.txt
Normal file
@ -0,0 +1,3 @@
|
||||
Fixes for new design.
|
||||
New button layout.
|
||||
Improve input error display.
|
2
fastlane/metadata/android/en-US/changelogs/5.txt
Normal file
@ -0,0 +1,2 @@
|
||||
Fix for event links with querystrings.
|
||||
New icon and banner as default toolbar image.
|
8
fastlane/metadata/android/en-US/changelogs/6.txt
Normal file
@ -0,0 +1,8 @@
|
||||
Rework help and about.
|
||||
Add settings with URL prefix selector.
|
||||
Add Maps button for location.
|
||||
Disable text field inputs - all fields can be edited in the calendar app.
|
||||
Change date/time format to RFC standard.
|
||||
Minor interface changes.
|
||||
Code cleanup and refactoring.
|
||||
Add code documentation.
|
2
fastlane/metadata/android/en-US/changelogs/7.txt
Normal file
@ -0,0 +1,2 @@
|
||||
Fix invalid default uri.
|
||||
Update about section.
|
BIN
fastlane/metadata/android/en-US/images/featureGraphic.png
Normal file
After Width: | Height: | Size: 22 KiB |
Before Width: | Height: | Size: 126 KiB After Width: | Height: | Size: 82 KiB |
BIN
fastlane/metadata/android/en-US/images/phoneScreenshots/2.png
Normal file
After Width: | Height: | Size: 92 KiB |
BIN
fastlane/metadata/android/en-US/images/phoneScreenshots/3.png
Normal file
After Width: | Height: | Size: 484 KiB |
BIN
fastlane/metadata/android/en-US/images/phoneScreenshots/4.png
Normal file
After Width: | Height: | Size: 78 KiB |
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
5
gradle/wrapper/gradle-wrapper.properties
vendored
@ -1,6 +1,7 @@
|
||||
#Wed Mar 25 12:20:43 CET 2020
|
||||
#Thu Jun 04 13:39:14 CEST 2020
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.4-all.zip
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-6.5-bin.zip
|
||||
distributionSha256Sum=23e7d37e9bb4f8dabb8a3ea7fdee9dd0428b9b1a71d298aefd65b11dccea220f
|
||||
|
22
gradlew
vendored
@ -1,5 +1,21 @@
|
||||
#!/usr/bin/env sh
|
||||
|
||||
#
|
||||
# Copyright 2015 the original author or authors.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# https://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#
|
||||
|
||||
##############################################################################
|
||||
##
|
||||
## Gradle start up script for UN*X
|
||||
@ -28,7 +44,7 @@ APP_NAME="Gradle"
|
||||
APP_BASE_NAME=`basename "$0"`
|
||||
|
||||
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||
DEFAULT_JVM_OPTS=""
|
||||
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
|
||||
|
||||
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
||||
MAX_FD="maximum"
|
||||
@ -109,8 +125,8 @@ if $darwin; then
|
||||
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
|
||||
fi
|
||||
|
||||
# For Cygwin, switch paths to Windows format before running java
|
||||
if $cygwin ; then
|
||||
# For Cygwin or MSYS, switch paths to Windows format before running java
|
||||
if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
|
||||
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
|
||||
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
|
||||
JAVACMD=`cygpath --unix "$JAVACMD"`
|
||||
|
18
gradlew.bat
vendored
@ -1,3 +1,19 @@
|
||||
@rem
|
||||
@rem Copyright 2015 the original author or authors.
|
||||
@rem
|
||||
@rem Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@rem you may not use this file except in compliance with the License.
|
||||
@rem You may obtain a copy of the License at
|
||||
@rem
|
||||
@rem https://www.apache.org/licenses/LICENSE-2.0
|
||||
@rem
|
||||
@rem Unless required by applicable law or agreed to in writing, software
|
||||
@rem distributed under the License is distributed on an "AS IS" BASIS,
|
||||
@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
@rem See the License for the specific language governing permissions and
|
||||
@rem limitations under the License.
|
||||
@rem
|
||||
|
||||
@if "%DEBUG%" == "" @echo off
|
||||
@rem ##########################################################################
|
||||
@rem
|
||||
@ -14,7 +30,7 @@ set APP_BASE_NAME=%~n0
|
||||
set APP_HOME=%DIRNAME%
|
||||
|
||||
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||
set DEFAULT_JVM_OPTS=
|
||||
set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
|
||||
|
||||
@rem Find java.exe
|
||||
if defined JAVA_HOME goto findJavaFromJavaHome
|
||||
|
1
icon.drawio
Normal file
@ -0,0 +1 @@
|
||||
<mxfile host="app.diagrams.net" modified="2020-08-26T11:23:24.586Z" agent="5.0 (X11)" etag="aOyZbSqfGqBfpLj75A79" version="13.6.5" type="device"><diagram id="3duFXleReQLFlbFXyRML" name="Page-1">5ZjLbqMwFIafhmUrzL3LIW2ni+moUhaTrQMOWDGYgknIPP2YYAi3FNJCGmmCFOEfY+D7j48vkroIsp8xjPxX6iIiKbKbSeqjpCiGafL/XDgUgmrqheDF2C0kcBKW+C8SoizUFLsoaVRklBKGo6bo0DBEDmtoMI7pvlltQ0nzqRH0UEdYOpB01T/YZX6hWop50l8Q9vzyycB4KK4EsKwsviTxoUv3NUl9ktRFTCkrzoJsgUjOruRS3Pd85mr1YjEK2ZgbVq/r1EM7Y5umKwu/kzd20O/KZnaQpOKLxduyQ4lg72OGlhF08vKeuyypts8CwkuAn8IkKsBvcIb4s+zqQ2Ve8AhMEnGebBFz/LLAYrpFC0pozJWQhrx1e4MJaUni/VDMUHb2y0HFk8chogFi8YFXETFnCQf2JwNVQ2h+zbxKhCJovKqpE1d+ItD2Y/ZXobIL33dgYaZLc7N9+b1d3Y2gHNM0dHN+R6hDzGNHdBVgjmEp8X6n2Zpit104g7IHeJdu1qQrYAOjS1uRe2jPBtsahu1x2tHnWVTpBq7LFuVLGFXZrc5I72EErLkgaZdEpDwckb0h2CX6oWHDITcUU0Cei5c5cQ/u5XXq1la3Az8ff3NQLaNyZMcF6gSQ+0cjZeqoHDUUtUDbx+PjmB4Yj84bcjZFKK0U0TVD6/FCm80K9VusGDOSLY6/Ga1oZ+vvtmLyXD2ZFU9GfsxoBdBuzAv9Zr2YvVu0MlTPrPq6Vhg3a8Xs3cK6MSsumh1d1wo7P66Yob7dixHLH94MjhI0Yp35lbV9uV+idKy6RrYCqt7wpdx3qvli9fgyxYKr3xd52JecAnYg+QXXiLzRBDNMQ35pTRmjAYdVVvhBsJdfYLTbcaK8sSDz8u24+zVMsHOfMBh/djasPJiPP4xrz4aBZt43/bMqoeagrncdLLXpl8wXjf1j1oB1PxwaYGc4y9UXgt1u9vGU4EvbPO3hH+h9y8V5El2vHcrD/2wHuJ4dvHjapT5eq231q0//AA==</diagram></mxfile>
|
2
icon.svg
@ -1,3 +1,3 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" style="background-color: rgb(255, 255, 255);" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="642px" height="642px" viewBox="-0.5 -0.5 642 642" content="<mxfile host="app.diagrams.net" modified="2020-03-26T14:54:10.768Z" agent="Mozilla/5.0 (X11; Linux x86_64; rv:74.0) Gecko/20100101 Firefox/74.0" etag="XsL7PBsKGEcMwgVGFdAw" version="12.9.3" type="device"><diagram id="wDqTZysBFCi2kShiBJaS" name="Page-1">1VjdcqIwGH0aLuuQ8KeXQms7u223u+7MXu5EiJBpIA6Eqvv0m0gAKThVF7aqjoaTL8dwTr6ERDO8eHOfolX0xAJMNagHG8241SAEYGyJH4lsC8S27AIIUxKooBqYkz9YgbpCcxLgrBHIGaOcrJqgz5IE+7yBoTRl62bYktHmv65QiFvA3Ee0jf4iAY8KdAydGn/AJIzKfwb2pKiJURms7iSLUMDWDQhv+IwlXHXxOU8IZ5p1F3Eu726qwZn4LGXEKGQspBitSDbyWSxgPxMhsyWKCZXSqsaO94Mt2NksqrHjvfwU3ZvjlCzPZJIEbkHgeI8kF3RfCErEzxNi4ttD5/ZxR+YWZO6OzJVkjvc9J/5rhpLgTOK6veN9peiNvCLRUVeOmPMIKxJ3R1Kz/iMd1Iw7zfBSxnhRijcepjLvypQqxtfsQG01plOc8GMa8PzmObhPZmTzAMDLM/j2G09uyhR4QzRXyaIGOt+W2ZOyPAmwZNE1w11HhOP5Cvmydi3mC4FFPKbiCohilSAyNqRI3v2uLNQgvipnPGWv2GOUpQJJWCK43CWhtIQ0aMx2L4kLXfdwMJVvgauO45TjzUFJQCW0mNwwizFPtyJENRirFN42L9f1HGGbCov25ocKRCrpw4q51l8UlAUn2AGsvu3oUvqgR+8sgBPndmq3LSheg1gA9SM9MMFgHpxiAfjYApT6akW02xI7pmtC95BR+940TNtPpv5NAPBIE4A+mAl9u9Cpbw/SWZOP55Au5YYbvvqVKGc6F6bc5EqEg5cm3PhKhAPWhQln9Czcu8XFhFPjFh4SdH8NGXCBt/Wm6JO26F1Ly2QozU96wupb88bD1nCam+PL0tz+HxPEISMG1BnYl6XzSZu5Kx3b7x9WP1tz0Lfozf3CMUP9E/ZpltOxdnZuEazBhD/ieU3eMvERfUQLTF9YRjhhiahaMM5ZLJQpA6aUhLKCs/Z5xkqSxZtQno2OFigj/ijjSGjsNrfi5x999JEWhtUwCFpmyyDD6DCoAk8wSFzW51a7ur2DY+PuLw==</diagram></mxfile>"><defs><style type="text/css">@import url(https://fonts.googleapis.com/css?family=Nunito);
@import url(https://fonts.googleapis.com/css?family=Roboto);
@import url(https://fonts.googleapis.com/css?family=PT+Serif);
@import url(https://fonts.googleapis.com/css?family=Liu+Jian+Mao+Cao);
@import url(https://fonts.googleapis.com/css?family=Quicksand);
@import url(https://fonts.googleapis.com/css?family=Klavika+Bold);
@import url(https://fonts.googleapis.com/css?family=Klavika);
</style></defs><g><rect x="0" y="0" width="640" height="640" fill="#ffffff" stroke="none" pointer-events="all"/><rect x="0" y="120" width="640" height="410" fill="#297da6" stroke="none" pointer-events="all"/><rect x="0" y="40" width="640" height="100" rx="6" ry="6" fill="#74b42b" stroke="none" pointer-events="all"/><rect x="510" y="0" width="60" height="110" rx="9" ry="9" fill="#ffffff" stroke="none" pointer-events="all"/><rect x="390" y="0" width="60" height="110" rx="9" ry="9" fill="#ffffff" stroke="none" pointer-events="all"/><rect x="190" y="0" width="60" height="110" rx="9" ry="9" fill="#ffffff" stroke="none" pointer-events="all"/><rect x="70" y="0" width="60" height="110" rx="9" ry="9" fill="#ffffff" stroke="none" pointer-events="all"/><rect x="520" y="10" width="40" height="90" rx="6" ry="6" fill="#42a3d2" stroke="none" pointer-events="all"/><rect x="400" y="10" width="40" height="90" rx="6" ry="6" fill="#42a3d2" stroke="none" pointer-events="all"/><rect x="80" y="10" width="40" height="90" rx="6" ry="6" fill="#42a3d2" stroke="none" pointer-events="all"/><rect x="200" y="10" width="40" height="90" rx="6" ry="6" fill="#42a3d2" stroke="none" pointer-events="all"/><rect x="0" y="490" width="640" height="150" rx="9" ry="9" fill="#297da6" stroke="none" pointer-events="all"/><path d="M 155 295 L 281.44 295 L 320 174 L 358.56 295 L 485 295 L 384.26 376.03 L 424.21 504 L 320 424.8 L 215.79 504 L 255.74 376.03 Z" fill="#ffffff" stroke="none" pointer-events="all"/></g></svg>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="361px" height="362px" viewBox="-0.5 -0.5 361 362" content="<mxfile host="app.diagrams.net" modified="2020-08-26T11:23:42.246Z" agent="5.0 (X11)" etag="jgrgKsVBq6YiCG3Uvhtx" version="13.6.5" type="device"><diagram id="3duFXleReQLFlbFXyRML" name="Page-1">5ZjLbqMwFIafhmUrzL3LIW2ni+moUhaTrQMOWDGYgknIPP2YYAi3FNJCGmmCFOEfY+D7j48vkroIsp8xjPxX6iIiKbKbSeqjpCiGafL/XDgUgmrqheDF2C0kcBKW+C8SoizUFLsoaVRklBKGo6bo0DBEDmtoMI7pvlltQ0nzqRH0UEdYOpB01T/YZX6hWop50l8Q9vzyycB4KK4EsKwsviTxoUv3NUl9ktRFTCkrzoJsgUjOruRS3Pd85mr1YjEK2ZgbVq/r1EM7Y5umKwu/kzd20O/KZnaQpOKLxduyQ4lg72OGlhF08vKeuyypts8CwkuAn8IkKsBvcIb4s+zqQ2Ve8AhMEnGebBFz/LLAYrpFC0pozJWQhrx1e4MJaUni/VDMUHb2y0HFk8chogFi8YFXETFnCQf2JwNVQ2h+zbxKhCJovKqpE1d+ItD2Y/ZXobIL33dgYaZLc7N9+b1d3Y2gHNM0dHN+R6hDzGNHdBVgjmEp8X6n2Zpit104g7IHeJdu1qQrYAOjS1uRe2jPBtsahu1x2tHnWVTpBq7LFuVLGFXZrc5I72EErLkgaZdEpDwckb0h2CX6oWHDITcUU0Cei5c5cQ/u5XXq1la3Az8ff3NQLaNyZMcF6gSQ+0cjZeqoHDUUtUDbx+PjmB4Yj84bcjZFKK0U0TVD6/FCm80K9VusGDOSLY6/Ga1oZ+vvtmLyXD2ZFU9GfsxoBdBuzAv9Zr2YvVu0MlTPrPq6Vhg3a8Xs3cK6MSsumh1d1wo7P66Yob7dixHLH94MjhI0Yp35lbV9uV+idKy6RrYCqt7wpdx3qvli9fgyxYKr3xd52JecAnYg+QXXiLzRBDNMQ35pTRmjAYdVVvhBsJdfYLTbcaK8sSDz8u24+zVMsHOfMBh/djasPJiPP4xrz4aBZt43/bMqoeagrncdLLXpl8wXjf1j1oB1PxwaYGc4y9UXgt1u9vGU4EvbPO3hH+h9y8V5El2vHcrD/2wHuJ4dvHjapT5eq231q0//AA==</diagram></mxfile>"><defs/><g><rect x="0" y="0" width="360" height="360" fill="none" stroke="none" pointer-events="all"/><rect x="80" y="80" width="200" height="60" rx="10.2" ry="10.2" fill="#74b42b" stroke="none" pointer-events="all"/><rect x="80" y="130" width="200" height="100" fill="#ffffff" stroke="none" pointer-events="all"/><rect x="80" y="150" width="200" height="130" rx="10.4" ry="10.4" fill="#ffffff" stroke="none" pointer-events="all"/><rect x="100" y="150" width="40" height="40" fill="#b3b3b3" stroke="none" pointer-events="all"/><rect x="160" y="150" width="40" height="40" fill="#cccccc" stroke="none" pointer-events="all"/><rect x="220" y="150" width="40" height="40" fill="#e6e6e6" stroke="none" pointer-events="all"/><rect x="100" y="210" width="40" height="40" fill="#cccccc" stroke="none" pointer-events="all"/><rect x="160" y="210" width="40" height="40" fill="#e6e6e6" stroke="none" pointer-events="all"/><rect x="220" y="210" width="40" height="40" fill="#ebebeb" stroke="none" pointer-events="all"/><ellipse cx="255" cy="245" rx="40" ry="40" fill="#ffffff" stroke="#cccccc" stroke-width="2" pointer-events="all"/><path d="M 227.5 237.67 L 248.57 237.67 L 255 217.5 L 261.43 237.67 L 282.5 237.67 L 265.71 251.17 L 272.37 272.5 L 255 259.3 L 237.63 272.5 L 244.29 251.17 Z" fill="#297da6" stroke="none" pointer-events="all"/><rect x="220" y="70" width="20" height="40" rx="3" ry="3" fill="#cccccc" stroke="#ffffff" stroke-width="2" pointer-events="all"/><rect x="120" y="70" width="20" height="40" rx="3" ry="3" fill="#cccccc" stroke="#ffffff" stroke-width="2" pointer-events="all"/></g></svg>
|
Before Width: | Height: | Size: 3.7 KiB After Width: | Height: | Size: 3.2 KiB |