16 Commits

30 changed files with 773 additions and 76 deletions

28
.idea/deploymentTargetDropDown.xml generated Normal file
View File

@ -0,0 +1,28 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="deploymentTargetDropDown">
<runningDeviceTargetSelectedWithDropDown>
<Target>
<type value="RUNNING_DEVICE_TARGET" />
<deviceKey>
<Key>
<type value="VIRTUAL_DEVICE_PATH" />
<value value="$USER_HOME$/.android/avd/Pixel_5_API_26.avd" />
</Key>
</deviceKey>
</Target>
</runningDeviceTargetSelectedWithDropDown>
<targetSelectedWithDropDown>
<Target>
<type value="QUICK_BOOT_TARGET" />
<deviceKey>
<Key>
<type value="VIRTUAL_DEVICE_PATH" />
<value value="$USER_HOME$/.android/avd/Pixel_5_API_26.avd" />
</Key>
</deviceKey>
</Target>
</targetSelectedWithDropDown>
<timeTargetWasSelectedWithDropDown value="2023-01-18T19:46:02.696157Z" />
</component>
</project>

2
.idea/misc.xml generated
View File

@ -3,8 +3,10 @@
<component name="DesignSurface"> <component name="DesignSurface">
<option name="filePathToZoomLevelMap"> <option name="filePathToZoomLevelMap">
<map> <map>
<entry key="../../../../layout/custom_preview.xml" value="0.3" />
<entry key="app/src/main/res/drawable-v24/ic_launcher_foreground.xml" value="0.2595" /> <entry key="app/src/main/res/drawable-v24/ic_launcher_foreground.xml" value="0.2595" />
<entry key="app/src/main/res/layout/activity_main.xml" value="0.33605072463768115" /> <entry key="app/src/main/res/layout/activity_main.xml" value="0.33605072463768115" />
<entry key="app/src/main/res/layout/activity_scan.xml" value="0.271875" />
<entry key="app/src/main/res/layout/activity_start.xml" value="0.33605072463768115" /> <entry key="app/src/main/res/layout/activity_start.xml" value="0.33605072463768115" />
</map> </map>
</option> </option>

View File

@ -1,7 +1,11 @@
# Bookwyrm-android # Bookwyrm-android
A crappy attempt at creating an Android application for Bookwyrm. Basically, it is just bookwyrm put into a 'webview' element. An Android application for Bookwyrm. Basically, it is just bookwyrm put into a 'webview' element.
What it does? It enables you to use BookWyrm on your Android phone without having to use a browser to go to it every time. What it does? It enables you to use BookWyrm on your Android phone without having to use a browser to go to it every time.
It can also open links to userpages of Bookwyrm users. It can also open links to userpages of Bookwyrm users and it can scan ISBN codes.
This application works on: Android 6 and above. This application works on: Android 6 and above.
And if you want to know, I am [`@StoryDragon@wyrms.de`](https://wyrms.de/user/storydragon) on BookWyrm.
For the ISBN-scanning I use the library zxing-android-embedded.
The barcode icon that is added for instances that do not have ISBN-scanning by default comes from the Remix Icon project.

View File

@ -3,16 +3,16 @@ plugins {
} }
android { android {
compileSdk 31 compileSdk 33
defaultConfig { defaultConfig {
applicationId "nl.privacydragon.bookwyrm" applicationId "nl.privacydragon.bookwyrm"
minSdk 23 minSdk 23
targetSdk 31 targetSdk 31
versionCode 3 versionCode 10
versionName "1.2.0" versionName "1.3.3"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" testInstrumentationRunner 'androidx.test.runner.AndroidJUnitRunner'
} }
buildTypes { buildTypes {
@ -29,9 +29,14 @@ android {
dependencies { dependencies {
implementation 'com.android.support:appcompat-v7:28.0.0' implementation 'androidx.appcompat:appcompat:1.6.0'
implementation 'com.android.support.constraint:constraint-layout:2.0.4' implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
testImplementation 'junit:junit:4.13.2' testImplementation 'junit:junit:4.13.2'
androidTestImplementation 'com.android.support.test:runner:1.0.2' androidTestImplementation 'androidx.test.ext:junit:1.1.5'
androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2' androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1'
implementation 'com.google.zxing:core:3.5.1'
implementation 'com.journeyapps:zxing-android-embedded:4.3.0@aar'
//implementation 'com.github.yuriy-budiyev:code-scanner:2.1.2'
} }

Binary file not shown.

Binary file not shown.

View File

@ -11,8 +11,8 @@
"type": "SINGLE", "type": "SINGLE",
"filters": [], "filters": [],
"attributes": [], "attributes": [],
"versionCode": 3, "versionCode": 10,
"versionName": "1.2.0", "versionName": "1.3.3",
"outputFile": "app-release.apk" "outputFile": "app-release.apk"
} }
], ],

View File

@ -1,8 +1,8 @@
package nl.privacydragon.bookwyrm; package nl.privacydragon.bookwyrm;
import android.content.Context; import android.content.Context;
import android.support.test.InstrumentationRegistry; import androidx.test.InstrumentationRegistry;
import android.support.test.runner.AndroidJUnit4; import androidx.test.runner.AndroidJUnit4;
import org.junit.Test; import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;

View File

@ -4,6 +4,11 @@
package="nl.privacydragon.bookwyrm"> package="nl.privacydragon.bookwyrm">
<uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-feature android:name="android.hardware.camera" />
<application <application
android:allowBackup="false" android:allowBackup="false"
@ -12,10 +17,12 @@
android:roundIcon="@mipmap/ic_launcher_wyrm_round" android:roundIcon="@mipmap/ic_launcher_wyrm_round"
android:supportsRtl="true" android:supportsRtl="true"
android:theme="@style/Theme.Bookwyrm"> android:theme="@style/Theme.Bookwyrm">
<meta-data
android:name="android.webkit.WebView.MetricsOptOut"
android:value="true" />
<activity <activity
android:name=".HandlerActivity" android:name=".HandlerActivity"
android:exported="true"> android:exported="true">
<intent-filter> <intent-filter>
<action android:name="android.intent.action.VIEW" /> <action android:name="android.intent.action.VIEW" />
@ -23,9 +30,9 @@
<category android:name="android.intent.category.BROWSABLE" /> <category android:name="android.intent.category.BROWSABLE" />
<data <data
android:scheme="https"
android:host="wyrms.de" android:host="wyrms.de"
android:pathPrefix="/user/" /> android:pathPrefix="/user/"
android:scheme="https" />
</intent-filter> </intent-filter>
<intent-filter> <intent-filter>
<action android:name="android.intent.action.VIEW" /> <action android:name="android.intent.action.VIEW" />
@ -34,9 +41,9 @@
<category android:name="android.intent.category.BROWSABLE" /> <category android:name="android.intent.category.BROWSABLE" />
<data <data
android:scheme="https"
android:host="bookwyrm.social" android:host="bookwyrm.social"
android:pathPrefix="/user/" /> android:pathPrefix="/user/"
android:scheme="https" />
</intent-filter> </intent-filter>
<intent-filter> <intent-filter>
<action android:name="android.intent.action.VIEW" /> <action android:name="android.intent.action.VIEW" />
@ -45,9 +52,9 @@
<category android:name="android.intent.category.BROWSABLE" /> <category android:name="android.intent.category.BROWSABLE" />
<data <data
android:scheme="https"
android:host="book.dansmonorage.blue" android:host="book.dansmonorage.blue"
android:pathPrefix="/user/" /> android:pathPrefix="/user/"
android:scheme="https" />
</intent-filter> </intent-filter>
<intent-filter> <intent-filter>
<action android:name="android.intent.action.VIEW" /> <action android:name="android.intent.action.VIEW" />
@ -56,9 +63,9 @@
<category android:name="android.intent.category.BROWSABLE" /> <category android:name="android.intent.category.BROWSABLE" />
<data <data
android:scheme="https"
android:host="yyyyy.club" android:host="yyyyy.club"
android:pathPrefix="/user/" /> android:pathPrefix="/user/"
android:scheme="https" />
</intent-filter> </intent-filter>
<intent-filter> <intent-filter>
<action android:name="android.intent.action.VIEW" /> <action android:name="android.intent.action.VIEW" />
@ -67,9 +74,9 @@
<category android:name="android.intent.category.BROWSABLE" /> <category android:name="android.intent.category.BROWSABLE" />
<data <data
android:scheme="https"
android:host="books.mxhdr.net" android:host="books.mxhdr.net"
android:pathPrefix="/user/" /> android:pathPrefix="/user/"
android:scheme="https" />
</intent-filter> </intent-filter>
<intent-filter> <intent-filter>
<action android:name="android.intent.action.VIEW" /> <action android:name="android.intent.action.VIEW" />
@ -78,9 +85,9 @@
<category android:name="android.intent.category.BROWSABLE" /> <category android:name="android.intent.category.BROWSABLE" />
<data <data
android:scheme="https"
android:host="ziurkes.group.lt" android:host="ziurkes.group.lt"
android:pathPrefix="/user/" /> android:pathPrefix="/user/"
android:scheme="https" />
</intent-filter> </intent-filter>
<intent-filter> <intent-filter>
<action android:name="android.intent.action.VIEW" /> <action android:name="android.intent.action.VIEW" />
@ -89,9 +96,9 @@
<category android:name="android.intent.category.BROWSABLE" /> <category android:name="android.intent.category.BROWSABLE" />
<data <data
android:scheme="https"
android:host="books.solarpunk.moe" android:host="books.solarpunk.moe"
android:pathPrefix="/user/" /> android:pathPrefix="/user/"
android:scheme="https" />
</intent-filter> </intent-filter>
<intent-filter> <intent-filter>
<action android:name="android.intent.action.VIEW" /> <action android:name="android.intent.action.VIEW" />
@ -100,9 +107,9 @@
<category android:name="android.intent.category.BROWSABLE" /> <category android:name="android.intent.category.BROWSABLE" />
<data <data
android:scheme="https"
android:host="reading.taks.garden" android:host="reading.taks.garden"
android:pathPrefix="/user/" /> android:pathPrefix="/user/"
android:scheme="https" />
</intent-filter> </intent-filter>
<intent-filter> <intent-filter>
<action android:name="android.intent.action.VIEW" /> <action android:name="android.intent.action.VIEW" />
@ -111,9 +118,9 @@
<category android:name="android.intent.category.BROWSABLE" /> <category android:name="android.intent.category.BROWSABLE" />
<data <data
android:scheme="https"
android:host="bookwyrm.spaceling.sh" android:host="bookwyrm.spaceling.sh"
android:pathPrefix="/user/" /> android:pathPrefix="/user/"
android:scheme="https" />
</intent-filter> </intent-filter>
<intent-filter> <intent-filter>
<action android:name="android.intent.action.VIEW" /> <action android:name="android.intent.action.VIEW" />
@ -122,9 +129,9 @@
<category android:name="android.intent.category.BROWSABLE" /> <category android:name="android.intent.category.BROWSABLE" />
<data <data
android:scheme="https"
android:host="lire.boitam.eu" android:host="lire.boitam.eu"
android:pathPrefix="/user/" /> android:pathPrefix="/user/"
android:scheme="https" />
</intent-filter> </intent-filter>
<intent-filter> <intent-filter>
<action android:name="android.intent.action.VIEW" /> <action android:name="android.intent.action.VIEW" />
@ -133,9 +140,9 @@
<category android:name="android.intent.category.BROWSABLE" /> <category android:name="android.intent.category.BROWSABLE" />
<data <data
android:scheme="https"
android:host="kirja.casa" android:host="kirja.casa"
android:pathPrefix="/user/" /> android:pathPrefix="/user/"
android:scheme="https" />
</intent-filter> </intent-filter>
<intent-filter> <intent-filter>
<action android:name="android.intent.action.VIEW" /> <action android:name="android.intent.action.VIEW" />
@ -144,9 +151,9 @@
<category android:name="android.intent.category.BROWSABLE" /> <category android:name="android.intent.category.BROWSABLE" />
<data <data
android:scheme="https"
android:host="books.badwolfbay.games" android:host="books.badwolfbay.games"
android:pathPrefix="/user/" /> android:pathPrefix="/user/"
android:scheme="https" />
</intent-filter> </intent-filter>
<intent-filter> <intent-filter>
<action android:name="android.intent.action.VIEW" /> <action android:name="android.intent.action.VIEW" />
@ -155,9 +162,9 @@
<category android:name="android.intent.category.BROWSABLE" /> <category android:name="android.intent.category.BROWSABLE" />
<data <data
android:scheme="https"
android:host="books.unexist.dev" android:host="books.unexist.dev"
android:pathPrefix="/user/" /> android:pathPrefix="/user/"
android:scheme="https" />
</intent-filter> </intent-filter>
<intent-filter> <intent-filter>
<action android:name="android.intent.action.VIEW" /> <action android:name="android.intent.action.VIEW" />
@ -166,9 +173,9 @@
<category android:name="android.intent.category.BROWSABLE" /> <category android:name="android.intent.category.BROWSABLE" />
<data <data
android:scheme="https"
android:host="bookwyrm.cincodenada.com" android:host="bookwyrm.cincodenada.com"
android:pathPrefix="/user/" /> android:pathPrefix="/user/"
android:scheme="https" />
</intent-filter> </intent-filter>
<intent-filter> <intent-filter>
<action android:name="android.intent.action.VIEW" /> <action android:name="android.intent.action.VIEW" />
@ -177,8 +184,74 @@
<category android:name="android.intent.category.BROWSABLE" /> <category android:name="android.intent.category.BROWSABLE" />
<data <data
android:scheme="https"
android:host="books.underscore.world" android:host="books.underscore.world"
android:pathPrefix="/user/"
android:scheme="https" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data
android:host="bookwyrm.tardis.pw"
android:pathPrefix="/user/"
android:scheme="https" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data
android:host="tankie.ml"
android:pathPrefix="/user/"
android:scheme="https" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data
android:host="masstoc.io"
android:pathPrefix="/user/"
android:scheme="https" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data
android:host="books.mennisch.net"
android:pathPrefix="/user/"
android:scheme="https" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data
android:host="bookwyrm.pt"
android:pathPrefix="/user/"
android:scheme="https" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data
android:scheme="https"
android:host="bookwyrm.lond.com.br"
android:pathPrefix="/user/" /> android:pathPrefix="/user/" />
</intent-filter> </intent-filter>
<intent-filter> <intent-filter>
@ -189,7 +262,249 @@
<data <data
android:scheme="https" android:scheme="https"
android:host="bookwyrm.tardis.pw" android:host="good.franv.site"
android:pathPrefix="/user/" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data
android:scheme="https"
android:host="books.solarpunkanarchism.org"
android:pathPrefix="/user/" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data
android:scheme="https"
android:host="shoko.one"
android:pathPrefix="/user/" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data
android:scheme="https"
android:host="bookwyrm.mennisch.net"
android:pathPrefix="/user/" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data
android:scheme="https"
android:host="library.southfox.me"
android:pathPrefix="/user/" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data
android:scheme="https"
android:host="bookrastinating.com"
android:pathPrefix="/user/" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data
android:scheme="https"
android:host="library.cybre.city"
android:pathPrefix="/user/" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data
android:scheme="https"
android:host="books.storydragon.nl"
android:pathPrefix="/user/" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data
android:scheme="https"
android:host="reading.unbl.ink"
android:pathPrefix="/user/" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data
android:scheme="https"
android:host="velhaestante.com.br"
android:pathPrefix="/user/" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data
android:scheme="https"
android:host="bookwyrm.gatti.ninja"
android:pathPrefix="/user/" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data
android:scheme="https"
android:host="books.theunseen.city"
android:pathPrefix="/user/" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data
android:scheme="https"
android:host="lore.livellosegreto.it"
android:pathPrefix="/user/" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data
android:scheme="https"
android:host="books.jascha.wtf"
android:pathPrefix="/user/" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data
android:scheme="https"
android:host="bw.diaspodon.fr"
android:pathPrefix="/user/" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data
android:scheme="https"
android:host="bookwyrm.tilde.zone"
android:pathPrefix="/user/" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data
android:scheme="https"
android:host="ramblingreaders.org"
android:pathPrefix="/user/" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data
android:scheme="https"
android:host="libros.mistli.net"
android:pathPrefix="/user/" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data
android:scheme="https"
android:host="lectura.social"
android:pathPrefix="/user/" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data
android:scheme="https"
android:host="orreadi.com"
android:pathPrefix="/user/" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data
android:scheme="https"
android:host="bookishbook.club"
android:pathPrefix="/user/" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data
android:scheme="https"
android:host="bookwyrm.tech"
android:pathPrefix="/user/" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data
android:scheme="https"
android:host="comelibros.club"
android:pathPrefix="/user/" /> android:pathPrefix="/user/" />
</intent-filter> </intent-filter>
</activity> </activity>

View File

@ -1,16 +1,41 @@
package nl.privacydragon.bookwyrm; package nl.privacydragon.bookwyrm;
import static androidx.core.content.ContextCompat.startActivity;
import android.Manifest;
import android.annotation.SuppressLint; import android.annotation.SuppressLint;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.content.SharedPreferences; import android.content.SharedPreferences;
import android.content.pm.PackageManager;
import android.graphics.Bitmap;
import android.net.Uri; import android.net.Uri;
import android.support.v7.app.AppCompatActivity; import android.os.Build;
//import android.support.v4.app.ActivityCompat;
//import android.support.v4.content.ContextCompat;
//import android.support.v7.app.AppCompatActivity;
import android.os.Bundle; import android.os.Bundle;
import android.util.Base64; import android.util.Base64;
import android.util.Log;
import android.view.KeyEvent;
import android.view.View;
import android.webkit.ConsoleMessage;
import android.webkit.JavascriptInterface;
import android.webkit.PermissionRequest;
import android.webkit.WebChromeClient;
import android.webkit.WebResourceRequest; import android.webkit.WebResourceRequest;
import android.webkit.WebSettings;
import android.webkit.WebView; import android.webkit.WebView;
import android.webkit.WebViewClient; import android.webkit.WebViewClient;
import android.widget.ProgressBar;
import android.widget.Toast;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;
import com.google.zxing.integration.android.IntentIntegrator;
import com.google.zxing.integration.android.IntentResult;
import java.io.IOException; import java.io.IOException;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
@ -31,6 +56,8 @@ import javax.crypto.spec.GCMParameterSpec;
public class HandlerActivity extends AppCompatActivity { public class HandlerActivity extends AppCompatActivity {
WebView myWebView;
ProgressBar LoadIndicator;
@SuppressLint("SetJavaScriptEnabled") @SuppressLint("SetJavaScriptEnabled")
@Override @Override
protected void onCreate(Bundle savedInstanceState) { protected void onCreate(Bundle savedInstanceState) {
@ -41,8 +68,23 @@ public class HandlerActivity extends AppCompatActivity {
String appLinkAction = appLinkIntent.getAction(); String appLinkAction = appLinkIntent.getAction();
Uri appLinkData = appLinkIntent.getData(); Uri appLinkData = appLinkIntent.getData();
// End of auto-generated stuff // End of auto-generated stuff
WebView myWebView = (WebView) findViewById(R.id.webview); LoadIndicator = (ProgressBar) findViewById(R.id.progressBar3);
myWebView = (WebView) findViewById(R.id.webview);
myWebView.setVisibility(View.GONE);
myWebView.getSettings().setJavaScriptEnabled(true); myWebView.getSettings().setJavaScriptEnabled(true);
myWebView.getSettings().setDomStorageEnabled(true);
myWebView.addJavascriptInterface(new Object()
{
@JavascriptInterface // For API 17+
public void performClick(String what)
{
if (!what.contains("[object Window]")) { //For some reason the function has to be called when the event listener is attached to the button. So, by adding in 'this', it is possible to make sure to only act when the thing that called the function is NOT the window, but the button.
ScanBarCode();
}
}
}, "scan");
//myWebView.addJavascriptInterface(new HandlerActivity.WebAppInterface(this), "Android");
//The user credentials are stored in the shared preferences, so first they have to be read from there. //The user credentials are stored in the shared preferences, so first they have to be read from there.
String defaultValue = "none"; String defaultValue = "none";
SharedPreferences sharedPref = HandlerActivity.this.getSharedPreferences(getString(R.string.server), Context.MODE_PRIVATE); SharedPreferences sharedPref = HandlerActivity.this.getSharedPreferences(getString(R.string.server), Context.MODE_PRIVATE);
@ -60,10 +102,15 @@ public class HandlerActivity extends AppCompatActivity {
String pathMaybe = appLinkData.getPath(); String pathMaybe = appLinkData.getPath();
String toGoServer = "bla"; String toGoServer = "bla";
if (pathMaybe.contains("user")) { if (pathMaybe.contains("user")) {
//If the path contains 'user', it is a user profile. //If the path contains 'user', it is a user profile, unless it is followed by something like 'review'.
String notAtUser = pathMaybe.substring(pathMaybe.indexOf("user") + 5); //This line gets the username. if (pathMaybe.contains("review") || pathMaybe.contains("generatednote") || pathMaybe.contains("quotation") || pathMaybe.contains("comment") ) {
String atUser = notAtUser + "@" + appLinkData.getHost(); //This appends @[HOST] to the string, so we have the full username thing needed. toGoServer = "https://" + appLinkData.getHost() + pathMaybe;
toGoServer = "https://" + server + "/user/" + atUser; }
else {
String notAtUser = pathMaybe.substring(pathMaybe.indexOf("user") + 5); //This line gets the username.
String atUser = notAtUser + "@" + appLinkData.getHost(); //This appends @[HOST] to the string, so we have the full username thing needed.
toGoServer = "https://" + server + "/user/" + atUser;
}
} else { } else {
startActivity(new Intent(HandlerActivity.this, nl.privacydragon.bookwyrm.StartActivity.class)); startActivity(new Intent(HandlerActivity.this, nl.privacydragon.bookwyrm.StartActivity.class));
} }
@ -129,32 +176,165 @@ public class HandlerActivity extends AppCompatActivity {
String finalToGoServer = toGoServer; String finalToGoServer = toGoServer;
myWebView.setWebViewClient(new HandlerActivity.MyWebViewClient() { myWebView.setWebViewClient(new HandlerActivity.MyWebViewClient() {
public void onPageFinished(WebView view, String url) { public void onPageFinished(WebView view, String url) {
LoadIndicator.setVisibility(View.GONE);
myWebView.setVisibility(View.VISIBLE);
view.loadUrl("javascript:(function() { document.getElementById('id_password').value = '" + passw + "'; ;})()"); view.loadUrl("javascript:(function() { document.getElementById('id_password').value = '" + passw + "'; ;})()");
view.loadUrl("javascript:(function() { document.getElementById('id_localname').value = '" + name + "'; ;})()"); view.loadUrl("javascript:(function() { document.getElementById('id_localname').value = '" + name + "'; ;})()");
view.loadUrl("javascript:(function() { if (window.location.href == '" + finalToGoServer + "') { document.getElementsByName(\"login\")[0].submit();} ;})()"); view.loadUrl("javascript:(function() { if (window.location.href == '" + finalToGoServer + "' && !/(review|generatednote|quotation|comment)/i.test(window.location.href)) { document.getElementsByName(\"login\")[0].submit();} ;})()");
view.loadUrl("javascript:(function() { if (window.location.href == 'https://" + server + "') { document.getElementsByName(\"login\")[0].submit();} ;})()");
view.loadUrl("javascript:(function() { if (/(review|generatednote|quotation|comment)/i.test(window.location.href)) {" +
"blocks = document.getElementsByClassName('block');" +
"for (let element of blocks){" +
"if (element.localName == 'header') { " +
"element.innerHTML = ` <a href=\"https://"+ server +"\" class=\"button\" data-back=\"\">\n" +
"<span class=\"icon icon-arrow-left\" aria-hidden=\"true\"></span>\n" +
"<span><b>Back to homeserver</b></span>\n" +
"</a>`;" +
"break;" +
"}" +
"}" +
"} ;})()");
view.loadUrl("javascript:(function() { " +
"if (document.querySelectorAll(\"[data-modal-open]\")[0]) {" +
"let ISBN_Button = document.querySelectorAll(\"[data-modal-open]\")[0];" +
"ISBN_Button.replaceWith(ISBN_Button.cloneNode(true));" +
"document.querySelectorAll(\"[data-modal-open]\")[0].addEventListener('click', () => {" +
"scan.performClick(this);" +
"});" +
"} else {" +
"let ISBN = document.createElement(\"div\");" +
"ISBN.class = 'control';" +
//"ISBN.class = 'button';" +
//"ISBN.type = 'button';" +
"ISBN.innerHTML = '<button class=\"button\" type=\"button\" onclick=\"scan.performClick(this)\"><svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\" width=\"24\" height=\"24\" aria-hidden=\"true\"><path fill=\"none\" d=\"M0 0h24v24H0z\"/><path d=\"M4 5v14h16V5H4zM3 3h18a1 1 0 0 1 1 1v16a1 1 0 0 1-1 1H3a1 1 0 0 1-1-1V4a1 1 0 0 1 1-1zm3 4h3v10H6V7zm4 0h2v10h-2V7zm3 0h1v10h-1V7zm2 0h3v10h-3V7z\"/></svg><span class=\"is-sr-only\">Search</span></button>';" +
"nav = document.getElementsByClassName(\"field has-addons\")[0];" +
"nav.appendChild(ISBN);" +
"}" +
";})()");
} }
}); });
/*myWebView.setWebChromeClient(new WebChromeClient(){
// Need to accept permissions to use the camera
@Override
public void onPermissionRequest(PermissionRequest request) {
String permission = Manifest.permission.WRITE_EXTERNAL_STORAGE;
int grant = ContextCompat.checkSelfPermission(HandlerActivity.this, permission);
if (grant != PackageManager.PERMISSION_GRANTED) {
String[] permission_list = new String[1];
permission_list[0] = permission;
ActivityCompat.requestPermissions(HandlerActivity.this, permission_list, 1);
}
request.grant(request.getResources());
final String[] requestedResources = request.getResources();
for (String r : requestedResources) {
if (r.equals(PermissionRequest.RESOURCE_PROTECTED_MEDIA_ID)) {
request.grant(new String[]{PermissionRequest.RESOURCE_VIDEO_CAPTURE});
break;
}
}
}
});*/
//Here, load the login page of the server. That actually does all that is needed. //Here, load the login page of the server. That actually does all that is needed.
//myWebView.loadUrl("https://serratus.github.io/quaggaJS/examples/live_w_locator.html");
myWebView.loadUrl(toGoServer); myWebView.loadUrl(toGoServer);
} }
public void ScanBarCode() {
String permission = Manifest.permission.CAMERA;
int grant = ContextCompat.checkSelfPermission(HandlerActivity.this, permission);
if (grant != PackageManager.PERMISSION_GRANTED) {
String[] permission_list = new String[1];
permission_list[0] = permission;
ActivityCompat.requestPermissions(HandlerActivity.this, permission_list, 1);
}
IntentIntegrator intentIntegrator = new IntentIntegrator(HandlerActivity.this);
intentIntegrator.setDesiredBarcodeFormats(intentIntegrator.EAN_13);
intentIntegrator.setBeepEnabled(true);
intentIntegrator.setCameraId(0);
intentIntegrator.setPrompt("SCAN");
intentIntegrator.setBarcodeImageEnabled(false);
intentIntegrator.initiateScan();
//return "blup";
//return "bla";
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
IntentResult Result = IntentIntegrator.parseActivityResult(requestCode, resultCode, data);
if (Result != null) {
if (Result.getContents() == null) {
Toast.makeText(this, "cancelled", Toast.LENGTH_SHORT).show();
} else {
Log.d("MainActivity", "Scanned");
myWebView.loadUrl("Javascript:(function() {document.getElementById('tour-search').value = " + Result.getContents() + ";" + "document.getElementById('search_input').value = " + Result.getContents() + ";" +
"document.getElementsByTagName('form')[0].submit(); ;})()");
LoadIndicator.setVisibility(View.VISIBLE);
}
} else {
super.onActivityResult(requestCode, resultCode, data);
}
}
/*public class WebAppInterface {
Context mContext;
//Instantiate the interface and set the context
WebAppInterface(Context c) {
mContext = c;
}
// Show a toast from the web page
@JavascriptInterface
public void showToast(String toast) {
Toast.makeText(mContext, toast, Toast.LENGTH_SHORT).show();
}
}*/
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
// Check if the key event was the Back button and if there's history
if ((keyCode == KeyEvent.KEYCODE_BACK) && myWebView.canGoBack()) {
myWebView.goBack();
return true;
}
// If it wasn't the Back key or there's no web page history, bubble up to the default
// system behavior (probably exit the activity)
return super.onKeyDown(keyCode, event);
}
//Here is code to make sure that links of the bookwyrm server are handled withing the webview client, instead of having it open in the default browser. //Here is code to make sure that links of the bookwyrm server are handled withing the webview client, instead of having it open in the default browser.
//Yes, I used the web for this too. //Yes, I used the web for this too.
private class MyWebViewClient extends WebViewClient { private class MyWebViewClient extends WebViewClient {
@Override @Override
public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request) { public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request) {
// ATTENTION: This was auto-generated to handle app links.
Intent appLinkIntent = getIntent();
String appLinkAction = appLinkIntent.getAction();
Uri appLinkData = appLinkIntent.getData();
// End of auto-generated stuff
String strangeHost = appLinkData.getHost();
SharedPreferences sharedPref = HandlerActivity.this.getSharedPreferences(getString(R.string.server), Context.MODE_PRIVATE); SharedPreferences sharedPref = HandlerActivity.this.getSharedPreferences(getString(R.string.server), Context.MODE_PRIVATE);
String defaultValue = "none"; String defaultValue = "none";
String server = sharedPref.getString(getString(R.string.server), defaultValue); String server = sharedPref.getString(getString(R.string.server), defaultValue);
if (server.equals(request.getUrl().getHost())) { if (server.equals(request.getUrl().getHost())) {
//If the server is the same as the bookwyrm, load it in the webview. //If the server is the same as the bookwyrm, load it in the webview.
return false; return false;
} else if (strangeHost.equals(request.getUrl().getHost())) {
return false;
} }
// Otherwise, it should go to the default browser instead. // Otherwise, it should go to the default browser instead.
Intent intent = new Intent(Intent.ACTION_VIEW, request.getUrl()); Intent intent = new Intent(Intent.ACTION_VIEW, request.getUrl());
startActivity(intent); startActivity(intent);
return true; return true;
} }
@Override
public void onPageStarted(WebView view, String url, Bitmap favicon) {
LoadIndicator.setVisibility(View.VISIBLE);
}
} }
} }

View File

@ -6,13 +6,15 @@ import android.content.SharedPreferences;
import android.graphics.Color; import android.graphics.Color;
import android.security.keystore.KeyGenParameterSpec; import android.security.keystore.KeyGenParameterSpec;
import android.security.keystore.KeyProperties; import android.security.keystore.KeyProperties;
import android.support.v7.app.AppCompatActivity; //import android.support.v7.app.AppCompatActivity;
import android.os.Bundle; import android.os.Bundle;
import android.util.Base64; import android.util.Base64;
import android.view.View; import android.view.View;
import android.widget.EditText; import android.widget.EditText;
import android.widget.TextView; import android.widget.TextView;
import androidx.appcompat.app.AppCompatActivity;
import java.io.IOException; import java.io.IOException;
import java.security.InvalidAlgorithmParameterException; import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException; import java.security.InvalidKeyException;

View File

@ -1,15 +1,31 @@
package nl.privacydragon.bookwyrm; package nl.privacydragon.bookwyrm;
import android.Manifest;
import android.annotation.SuppressLint; import android.annotation.SuppressLint;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.content.SharedPreferences; import android.content.SharedPreferences;
import android.support.v7.app.AppCompatActivity; //import android.support.v7.app.AppCompatActivity;
import android.content.pm.PackageManager;
import android.graphics.Bitmap;
import android.os.Bundle; import android.os.Bundle;
import android.util.Base64; import android.util.Base64;
import android.util.Log;
import android.view.KeyEvent;
import android.view.View;
import android.webkit.JavascriptInterface;
import android.webkit.WebResourceRequest; import android.webkit.WebResourceRequest;
import android.webkit.WebView; import android.webkit.WebView;
import android.webkit.WebViewClient; import android.webkit.WebViewClient;
import android.widget.ProgressBar;
import android.widget.Toast;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;
import com.google.zxing.integration.android.IntentIntegrator;
import com.google.zxing.integration.android.IntentResult;
import java.io.IOException; import java.io.IOException;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
@ -29,14 +45,28 @@ import javax.crypto.NoSuchPaddingException;
import javax.crypto.spec.GCMParameterSpec; import javax.crypto.spec.GCMParameterSpec;
public class StartActivity extends AppCompatActivity { public class StartActivity extends AppCompatActivity {
WebView myWebView;
ProgressBar LoadIndicator;
@SuppressLint("SetJavaScriptEnabled") @SuppressLint("SetJavaScriptEnabled")
@Override @Override
protected void onCreate(Bundle savedInstanceState) { protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
setContentView(R.layout.activity_start); setContentView(R.layout.activity_start);
WebView myWebView = (WebView) findViewById(R.id.webview); LoadIndicator = (ProgressBar) findViewById(R.id.progressBar3);
myWebView = (WebView) findViewById(R.id.webview);
myWebView.setVisibility(View.GONE);
myWebView.getSettings().setJavaScriptEnabled(true); myWebView.getSettings().setJavaScriptEnabled(true);
myWebView.addJavascriptInterface(new Object()
{
@JavascriptInterface // For API 17+
public void performClick(String what)
{
if (!what.contains("[object Window]")) { //For some reason the function has to be called when the event listener is attached to the button. So, by adding in 'this', it is possible to make sure to only act when the thing that called the function is NOT the window, but the button.
ScanBarCode();
}
}
}, "scan");
//The user credentials are stored in the shared preferences, so first they have to be read from there. //The user credentials are stored in the shared preferences, so first they have to be read from there.
String defaultValue = "none"; String defaultValue = "none";
SharedPreferences sharedPref = StartActivity.this.getSharedPreferences(getString(R.string.server), Context.MODE_PRIVATE); SharedPreferences sharedPref = StartActivity.this.getSharedPreferences(getString(R.string.server), Context.MODE_PRIVATE);
@ -108,16 +138,85 @@ public class StartActivity extends AppCompatActivity {
//A webviewclient thing is needed for some stuff. To automatically log in, the credentials are put in the form by the javascript that is loaded once the page is fully loaded. Then it is automatically submitted if the current page is the login page. //A webviewclient thing is needed for some stuff. To automatically log in, the credentials are put in the form by the javascript that is loaded once the page is fully loaded. Then it is automatically submitted if the current page is the login page.
myWebView.setWebViewClient(new MyWebViewClient(){ myWebView.setWebViewClient(new MyWebViewClient(){
public void onPageFinished(WebView view, String url) { public void onPageFinished(WebView view, String url) {
LoadIndicator.setVisibility(View.GONE);
myWebView.setVisibility(View.VISIBLE);
view.loadUrl("javascript:(function() { document.getElementById('id_password_confirm').value = '" + passw + "'; ;})()"); view.loadUrl("javascript:(function() { document.getElementById('id_password_confirm').value = '" + passw + "'; ;})()");
view.loadUrl("javascript:(function() { document.getElementById('id_localname_confirm').value = '" + name + "'; ;})()"); view.loadUrl("javascript:(function() { document.getElementById('id_localname_confirm').value = '" + name + "'; ;})()");
view.loadUrl("javascript:(function() { if (window.location.href == 'https://" + server + "/login') { document.getElementsByName(\"login-confirm\")[0].submit();} ;})()"); view.loadUrl("javascript:(function() { if (window.location.href == 'https://" + server + "/login') { document.getElementsByName(\"login-confirm\")[0].submit();} ;})()");
view.loadUrl("javascript:(function() { " +
"if (document.querySelectorAll(\"[data-modal-open]\")[0]) {" +
"let ISBN_Button = document.querySelectorAll(\"[data-modal-open]\")[0];" +
"ISBN_Button.replaceWith(ISBN_Button.cloneNode(true));" +
"document.querySelectorAll(\"[data-modal-open]\")[0].addEventListener('click', () => {" +
"scan.performClick(this);" +
"});" +
"} else {" +
"let ISBN = document.createElement(\"div\");" +
"ISBN.class = 'control';" +
//"ISBN.class = 'button';" +
//"ISBN.type = 'button';" +
"ISBN.innerHTML = '<button class=\"button\" type=\"button\" onclick=\"scan.performClick(this)\"><svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\" width=\"24\" height=\"24\" aria-hidden=\"true\"><path fill=\"none\" d=\"M0 0h24v24H0z\"/><path d=\"M4 5v14h16V5H4zM3 3h18a1 1 0 0 1 1 1v16a1 1 0 0 1-1 1H3a1 1 0 0 1-1-1V4a1 1 0 0 1 1-1zm3 4h3v10H6V7zm4 0h2v10h-2V7zm3 0h1v10h-1V7zm2 0h3v10h-3V7z\"/></svg><span class=\"is-sr-only\">Search</span></button>';" +
"nav = document.getElementsByClassName(\"field has-addons\")[0];" +
"nav.appendChild(ISBN);" +
"}" +
";})()"); //This lines replace the ISBN-scan button event listener with one that points to the on-device scanning implementation, if it is available on the instance. If not, the button is added.
} }
}); });
//Here, load the login page of the server. That actually does all that is needed. //Here, load the login page of the server. That actually does all that is needed.
myWebView.loadUrl("https://" + server + "/login"); myWebView.loadUrl("https://" + server + "/login");
} }
public void ScanBarCode() {
String permission = Manifest.permission.CAMERA;
int grant = ContextCompat.checkSelfPermission(StartActivity.this, permission);
if (grant != PackageManager.PERMISSION_GRANTED) {
String[] permission_list = new String[1];
permission_list[0] = permission;
ActivityCompat.requestPermissions(StartActivity.this, permission_list, 1);
}
IntentIntegrator intentIntegrator = new IntentIntegrator(StartActivity.this);
intentIntegrator.setDesiredBarcodeFormats(intentIntegrator.EAN_13);
intentIntegrator.setBeepEnabled(false);
intentIntegrator.setCameraId(0);
intentIntegrator.setPrompt("SCAN ISBN");
intentIntegrator.setBarcodeImageEnabled(false);
intentIntegrator.initiateScan();
//return "blup";
//return "bla";
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
IntentResult Result = IntentIntegrator.parseActivityResult(requestCode, resultCode, data);
if (Result != null) {
if (Result.getContents() == null) {
Toast.makeText(this, "cancelled", Toast.LENGTH_SHORT).show();
} else {
Log.d("MainActivity", "Scanned");
myWebView.loadUrl("Javascript:(function() {document.getElementById('tour-search').value = " + Result.getContents() + ";" + "document.getElementById('search_input').value = " + Result.getContents() + ";" +
"document.getElementsByTagName('form')[0].submit(); ;})()");
LoadIndicator.setVisibility(View.VISIBLE);
}
} else {
super.onActivityResult(requestCode, resultCode, data);
}
}
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
// Check if the key event was the Back button and if there's history
if ((keyCode == KeyEvent.KEYCODE_BACK) && myWebView.canGoBack()) {
myWebView.goBack();
return true;
}
// If it wasn't the Back key or there's no web page history, bubble up to the default
// system behavior (probably exit the activity)
return super.onKeyDown(keyCode, event);
}
//Here is code to make sure that links of the bookwyrm server are handled withing the webview client, instead of having it open in the default browser. //Here is code to make sure that links of the bookwyrm server are handled withing the webview client, instead of having it open in the default browser.
//Yes, I used the web for this too. //Yes, I used the web for this too.
private class MyWebViewClient extends WebViewClient { private class MyWebViewClient extends WebViewClient {
@ -135,5 +234,10 @@ public class StartActivity extends AppCompatActivity {
startActivity(intent); startActivity(intent);
return true; return true;
} }
@Override
public void onPageStarted(WebView view, String url, Bitmap favicon) {
LoadIndicator.setVisibility(View.VISIBLE);
}
} }
} }

View File

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools" xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent" android:layout_width="match_parent"
@ -26,7 +26,7 @@
android:id="@+id/Instance" android:id="@+id/Instance"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginStart="5dp" android:layout_marginStart="10dp"
android:layout_marginEnd="1dp" android:layout_marginEnd="1dp"
android:layout_marginBottom="262dp" android:layout_marginBottom="262dp"
android:hint="bookwyrm.social" android:hint="bookwyrm.social"
@ -41,7 +41,7 @@
android:id="@+id/Username" android:id="@+id/Username"
android:layout_width="409dp" android:layout_width="409dp"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginStart="1dp" android:layout_marginStart="10dp"
android:layout_marginEnd="1dp" android:layout_marginEnd="1dp"
android:layout_marginBottom="284dp" android:layout_marginBottom="284dp"
android:hint="Username" android:hint="Username"
@ -55,7 +55,7 @@
<EditText <EditText
android:id="@+id/Password" android:id="@+id/Password"
android:layout_width="409dp" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginStart="10dp" android:layout_marginStart="10dp"
android:layout_marginEnd="1dp" android:layout_marginEnd="1dp"
@ -89,10 +89,10 @@
android:id="@+id/textView2" android:id="@+id/textView2"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginStart="16dp" android:layout_marginStart="10dp"
android:layout_marginTop="76dp" android:layout_marginTop="76dp"
android:layout_marginEnd="185dp" android:layout_marginEnd="185dp"
android:layout_marginBottom="35dp" android:layout_marginBottom="10dp"
android:text="Instance. WITHOUT the https part" android:text="Instance. WITHOUT the https part"
app:layout_constraintBottom_toTopOf="@+id/Instance" app:layout_constraintBottom_toTopOf="@+id/Instance"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"
@ -107,7 +107,7 @@
android:layout_marginStart="10dp" android:layout_marginStart="10dp"
android:layout_marginTop="24dp" android:layout_marginTop="24dp"
android:layout_marginEnd="41dp" android:layout_marginEnd="41dp"
android:layout_marginBottom="35dp" android:layout_marginBottom="10dp"
android:text="Username" android:text="Username"
app:layout_constraintBottom_toTopOf="@+id/Username" app:layout_constraintBottom_toTopOf="@+id/Username"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"
@ -115,6 +115,21 @@
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/Instance" /> app:layout_constraintTop_toBottomOf="@+id/Instance" />
<TextView
android:id="@+id/textView6"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="10dp"
android:layout_marginTop="24dp"
android:layout_marginEnd="340dp"
android:layout_marginBottom="10dp"
android:text="Password"
app:layout_constraintBottom_toTopOf="@+id/Password"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/Username" />
<Button <Button
android:id="@+id/button" android:id="@+id/button"
android:layout_width="wrap_content" android:layout_width="wrap_content"
@ -147,4 +162,4 @@
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/button" /> app:layout_constraintTop_toBottomOf="@+id/button" />
</android.support.constraint.ConstraintLayout> </androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -1,16 +1,26 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools" xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
tools:context=".StartActivity"> tools:context=".StartActivity">
<WebView <WebView
android:id="@+id/webview" android:id="@+id/webview"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent" />
/>
<ProgressBar
android:id="@+id/progressBar3"
style="?android:attr/progressBarStyleHorizontal"
android:indeterminate="true"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="715dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
</android.support.constraint.ConstraintLayout>

View File

@ -1,6 +1,6 @@
<resources xmlns:tools="http://schemas.android.com/tools"> <resources xmlns:tools="http://schemas.android.com/tools">
<!-- Base application theme. --> <!-- Base application theme. -->
<style name="Theme.Bookwyrm" parent="Theme.AppCompat.Light.DarkActionBar"> <style name="Theme.Bookwyrm" parent="Theme.AppCompat">
<!-- Primary brand color. --> <!-- Primary brand color. -->
<item name="colorPrimary">#3298DC</item> <item name="colorPrimary">#3298DC</item>
<item name="colorPrimaryDark">#1B557C</item> <item name="colorPrimaryDark">#1B557C</item>

View File

@ -1,6 +1,6 @@
<resources xmlns:tools="http://schemas.android.com/tools"> <resources xmlns:tools="http://schemas.android.com/tools">
<!-- Base application theme. --> <!-- Base application theme. -->
<style name="Theme.Bookwyrm" parent="Theme.AppCompat.Light.DarkActionBar"> <style name="Theme.Bookwyrm" parent="Theme.AppCompat">
<!-- Primary brand color. --> <!-- Primary brand color. -->
<item name="colorPrimary">#3298DC</item> <item name="colorPrimary">#3298DC</item>
<item name="colorPrimaryDark">#1B557C</item> <item name="colorPrimaryDark">#1B557C</item>

View File

@ -0,0 +1,3 @@
* Fixed a bug with the barcode scanning. Now you can scan barcodes again.
* Dependencies have been updated to newest versions.
* More Bookwyrm instances have been added.

View File

@ -0,0 +1,3 @@
Initial release for F-Droid.
* Added support for four more BookWyrm instances.

View File

@ -0,0 +1,5 @@
* Added a loading bar
* You can now scan ISBN's, on any instance!
More technical change:
* Mitigated the project to use Androidx libraries, for that is necessary for the ISBN scanning...

View File

@ -0,0 +1,6 @@
* Improved the loading bar.
* The ISBN-scanning feature now works by simply clicking the ISBN button that is used by the instances that have scanning already available.
* For instances that do not support the scanning server-side, there is now instead of the text a button for ISBN-scanning, similar to the standard one.
* More bookwyrm instances added to the ones that can be opened in the app.
* Small bug-fix, so now only ISBN-codes (And other EAN-13 codes) will be scanned.
* Another bug-fix. The modified back button works again.

View File

@ -0,0 +1,2 @@
* Changed the initial screen to dark mode.
* The login screen things are now better aligned.

View File

@ -1,2 +1,10 @@
This is a, probably crappy, Android client for BookWyrm. This is an Android client for BookWyrm a federated social network for tracking your reading, talking about books, writing reviews, and discovering what to read next. It is just BookWyrm put into a webview element, nothing special but it adds some convenience on top:
It is just BookWyrm put into a webview element, nothing special.
* bookwyrm links can be made to open with the app (e.g. clicking on the link to someone's userprofile will open that from your own bookwyrm instance)
* thanks to that, you can immediately follow them easily if you want.
* it lets you easily return to your own home timeline when viewing something like posts, on another bookwyrm instance, because the 'back' button is then modified for that.
* You can also search for books by scanning the ISBN, no matter what instance of Bookwyrm you use.
<b>This application is <u>not</u> an official client!</b> (An official client does not exist yet, as far as I know)
The ISBN scanning feature is created with the zxing-android-embedded library.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 302 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 318 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 247 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 203 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 45 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 MiB

View File

@ -15,3 +15,6 @@ org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8
# resources declared in the library itself and none from the library's dependencies, # resources declared in the library itself and none from the library's dependencies,
# thereby reducing the size of the R class for that library # thereby reducing the size of the R class for that library
android.nonTransitiveRClass=true android.nonTransitiveRClass=true
android.useAndroidX=true
android.enableJetifier=true

View File

@ -10,7 +10,9 @@ dependencyResolutionManagement {
repositories { repositories {
google() google()
mavenCentral() mavenCentral()
//maven { url 'https://jitpack.io' }
} }
} }
rootProject.name = "Bookwyrm" rootProject.name = "Bookwyrm"
include ':app' include ':app'