Compare commits
27 Commits
Author | SHA1 | Date | |
---|---|---|---|
ebb434b1b3 | |||
f79d9300ed | |||
78b7654b8d | |||
e55426bc90 | |||
5c8b038a99 | |||
4cfbee2524 | |||
6b44f589ac | |||
2c549830ed | |||
ad5a1dca8b | |||
8037938adf | |||
928e922a8f | |||
3fc7cc242d | |||
645acfc014 | |||
f548c4e596 | |||
b9fd322d32 | |||
be020bdfcd | |||
6be6081f27 | |||
303eed4e3f | |||
f7f28ea807 | |||
75a4874225 | |||
989299cf31 | |||
21a877d6b1 | |||
012de9e47d | |||
5d6e61469d | |||
7c7689ec1b | |||
c6bc914608 | |||
c75cf18dd2 |
1
.idea/.name
generated
Normal file
1
.idea/.name
generated
Normal file
@ -0,0 +1 @@
|
|||||||
|
Bookwyrm
|
2
.idea/compiler.xml
generated
2
.idea/compiler.xml
generated
@ -1,6 +1,6 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<project version="4">
|
<project version="4">
|
||||||
<component name="CompilerConfiguration">
|
<component name="CompilerConfiguration">
|
||||||
<bytecodeTargetLevel target="11" />
|
<bytecodeTargetLevel target="17" />
|
||||||
</component>
|
</component>
|
||||||
</project>
|
</project>
|
8
.idea/deploymentTargetDropDown.xml
generated
8
.idea/deploymentTargetDropDown.xml
generated
@ -1,9 +1,9 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<project version="4">
|
<project version="4">
|
||||||
<component name="deploymentTargetDropDown">
|
<component name="deploymentTargetDropDown">
|
||||||
<runningDeviceTargetSelectedWithDropDown>
|
<targetSelectedWithDropDown>
|
||||||
<Target>
|
<Target>
|
||||||
<type value="RUNNING_DEVICE_TARGET" />
|
<type value="QUICK_BOOT_TARGET" />
|
||||||
<deviceKey>
|
<deviceKey>
|
||||||
<Key>
|
<Key>
|
||||||
<type value="VIRTUAL_DEVICE_PATH" />
|
<type value="VIRTUAL_DEVICE_PATH" />
|
||||||
@ -11,7 +11,7 @@
|
|||||||
</Key>
|
</Key>
|
||||||
</deviceKey>
|
</deviceKey>
|
||||||
</Target>
|
</Target>
|
||||||
</runningDeviceTargetSelectedWithDropDown>
|
</targetSelectedWithDropDown>
|
||||||
<timeTargetWasSelectedWithDropDown value="2022-02-14T18:35:03.252054Z" />
|
<timeTargetWasSelectedWithDropDown value="2023-01-19T17:01:06.009496Z" />
|
||||||
</component>
|
</component>
|
||||||
</project>
|
</project>
|
7
.idea/gradle.xml
generated
7
.idea/gradle.xml
generated
@ -1,18 +1,19 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<project version="4">
|
<project version="4">
|
||||||
|
<component name="GradleMigrationSettings" migrationVersion="1" />
|
||||||
<component name="GradleSettings">
|
<component name="GradleSettings">
|
||||||
<option name="linkedExternalProjectsSettings">
|
<option name="linkedExternalProjectsSettings">
|
||||||
<GradleProjectSettings>
|
<GradleProjectSettings>
|
||||||
<option name="testRunner" value="GRADLE" />
|
<option name="testRunner" value="CHOOSE_PER_TEST" />
|
||||||
<option name="distributionType" value="DEFAULT_WRAPPED" />
|
|
||||||
<option name="externalProjectPath" value="$PROJECT_DIR$" />
|
<option name="externalProjectPath" value="$PROJECT_DIR$" />
|
||||||
|
<option name="gradleJvm" value="#GRADLE_LOCAL_JAVA_HOME" />
|
||||||
<option name="modules">
|
<option name="modules">
|
||||||
<set>
|
<set>
|
||||||
<option value="$PROJECT_DIR$" />
|
<option value="$PROJECT_DIR$" />
|
||||||
<option value="$PROJECT_DIR$/app" />
|
<option value="$PROJECT_DIR$/app" />
|
||||||
</set>
|
</set>
|
||||||
</option>
|
</option>
|
||||||
<option name="resolveModulePerSourceSet" value="false" />
|
<option name="resolveExternalAnnotations" value="false" />
|
||||||
</GradleProjectSettings>
|
</GradleProjectSettings>
|
||||||
</option>
|
</option>
|
||||||
</component>
|
</component>
|
||||||
|
5
.idea/misc.xml
generated
5
.idea/misc.xml
generated
@ -1,15 +1,16 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<project version="4">
|
<project version="4">
|
||||||
<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>
|
||||||
</component>
|
</component>
|
||||||
<component name="ProjectRootManager" version="2" languageLevel="JDK_11" default="true" project-jdk-name="Android Studio default JDK" project-jdk-type="JavaSDK">
|
<component name="ProjectRootManager" version="2" languageLevel="JDK_17" default="true" project-jdk-name="corretto-17" project-jdk-type="JavaSDK">
|
||||||
<output url="file://$PROJECT_DIR$/build/classes" />
|
<output url="file://$PROJECT_DIR$/build/classes" />
|
||||||
</component>
|
</component>
|
||||||
<component name="ProjectType">
|
<component name="ProjectType">
|
||||||
|
16
README.md
16
README.md
@ -1,3 +1,17 @@
|
|||||||
# Bookwyrm-android
|
# Bookwyrm-android
|
||||||
A crappy attempt at creating an Android application for Bookwyrm. Basically, it is just bookwyrm put into a 'webview' element. Also, I am not sure whether the credentials are stored in a safe way, so be warned! (If you know how to make it safer, please do a pull request!)
|
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.
|
||||||
|
It can also open links to userpages of Bookwyrm users and it can scan ISBN codes.
|
||||||
|
|
||||||
|
This application works on: Android 6 and above.
|
||||||
|
|
||||||
|
And if you want to know, I am [`@StoryDragon@books.storydragon.nl`](https://books.storydragon.nl/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.
|
||||||
|
|
||||||
|
[<img src="https://fdroid.gitlab.io/artwork/badge/get-it-on.png"
|
||||||
|
alt="Get it on F-Droid"
|
||||||
|
height="80">](https://f-droid.org/packages/nl.privacydragon.bookwyrm/)
|
||||||
|
|
||||||
|
Or download the latest APK from the [Releases Section](https://github.com/PrivacyDragon/Bookwyrm_Android/releases/latest).
|
||||||
|
@ -3,16 +3,16 @@ plugins {
|
|||||||
}
|
}
|
||||||
|
|
||||||
android {
|
android {
|
||||||
compileSdk 31
|
compileSdk 34
|
||||||
|
|
||||||
defaultConfig {
|
defaultConfig {
|
||||||
applicationId "nl.privacydragon.bookwyrm"
|
applicationId "nl.privacydragon.bookwyrm"
|
||||||
minSdk 21
|
minSdk 23
|
||||||
targetSdk 31
|
targetSdk 34
|
||||||
versionCode 1
|
versionCode 12
|
||||||
versionName "1.0"
|
versionName "1.3.5"
|
||||||
|
|
||||||
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
|
testInstrumentationRunner 'androidx.test.runner.AndroidJUnitRunner'
|
||||||
}
|
}
|
||||||
|
|
||||||
buildTypes {
|
buildTypes {
|
||||||
@ -25,13 +25,18 @@ android {
|
|||||||
sourceCompatibility JavaVersion.VERSION_1_8
|
sourceCompatibility JavaVersion.VERSION_1_8
|
||||||
targetCompatibility JavaVersion.VERSION_1_8
|
targetCompatibility JavaVersion.VERSION_1_8
|
||||||
}
|
}
|
||||||
|
namespace 'nl.privacydragon.bookwyrm'
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
|
|
||||||
implementation 'com.android.support:appcompat-v7:28.0.0'
|
implementation 'androidx.appcompat:appcompat:1.7.0'
|
||||||
implementation 'com.android.support.constraint:constraint-layout:2.0.4'
|
implementation 'androidx.constraintlayout:constraintlayout:2.2.0'
|
||||||
|
implementation platform('org.jetbrains.kotlin:kotlin-bom:2.1.0')
|
||||||
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.2.1'
|
||||||
androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
|
androidTestImplementation 'androidx.test.espresso:espresso-core:3.6.1'
|
||||||
|
implementation 'com.google.zxing:core:3.5.3'
|
||||||
|
implementation 'com.journeyapps:zxing-android-embedded:4.3.0@aar'
|
||||||
|
|
||||||
}
|
}
|
Binary file not shown.
BIN
app/release/Bookwyrm-v1.3.5.apk
Normal file
BIN
app/release/Bookwyrm-v1.3.5.apk
Normal file
Binary file not shown.
@ -11,10 +11,27 @@
|
|||||||
"type": "SINGLE",
|
"type": "SINGLE",
|
||||||
"filters": [],
|
"filters": [],
|
||||||
"attributes": [],
|
"attributes": [],
|
||||||
"versionCode": 1,
|
"versionCode": 12,
|
||||||
"versionName": "1.0",
|
"versionName": "1.3.5",
|
||||||
"outputFile": "app-release.apk"
|
"outputFile": "app-release.apk"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"elementType": "File"
|
"elementType": "File",
|
||||||
|
"baselineProfiles": [
|
||||||
|
{
|
||||||
|
"minApi": 28,
|
||||||
|
"maxApi": 30,
|
||||||
|
"baselineProfiles": [
|
||||||
|
"baselineProfiles/1/app-release.dm"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"minApi": 31,
|
||||||
|
"maxApi": 2147483647,
|
||||||
|
"baselineProfiles": [
|
||||||
|
"baselineProfiles/0/app-release.dm"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"minSdkVersionForDexing": 23
|
||||||
}
|
}
|
@ -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;
|
||||||
|
@ -1,14 +1,757 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
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="true"
|
android:allowBackup="false"
|
||||||
android:icon="@mipmap/ic_launcher_wyrm"
|
android:icon="@mipmap/ic_launcher_wyrm"
|
||||||
android:label="@string/app_name"
|
android:label="@string/app_name"
|
||||||
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
|
||||||
|
android:name=".HandlerActivity"
|
||||||
|
android:exported="true">
|
||||||
|
<intent-filter android:autoVerify="true">
|
||||||
|
<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" />
|
||||||
|
<data android:host="wyrms.de" />
|
||||||
|
</intent-filter>
|
||||||
|
<intent-filter android:autoVerify="true">
|
||||||
|
<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" />
|
||||||
|
<data android:host="bookwyrm.social" />
|
||||||
|
</intent-filter>
|
||||||
|
<intent-filter android:autoVerify="true">
|
||||||
|
<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" />
|
||||||
|
<data android:host="book.dansmonorage.blue" />
|
||||||
|
</intent-filter>
|
||||||
|
<intent-filter android:autoVerify="true">
|
||||||
|
<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" />
|
||||||
|
<data android:host="yyyyy.club" />
|
||||||
|
</intent-filter>
|
||||||
|
<intent-filter android:autoVerify="true">
|
||||||
|
<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" />
|
||||||
|
<data android:host="books.mxhdr.net" />
|
||||||
|
</intent-filter>
|
||||||
|
<intent-filter android:autoVerify="true">
|
||||||
|
<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" />
|
||||||
|
<data android:host="ziurkes.group.lt" />
|
||||||
|
</intent-filter>
|
||||||
|
<intent-filter android:autoVerify="true">
|
||||||
|
<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" />
|
||||||
|
<data android:host="books.solarpunk.moe" />
|
||||||
|
</intent-filter>
|
||||||
|
<intent-filter android:autoVerify="true">
|
||||||
|
<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" />
|
||||||
|
<data android:host="reading.taks.garden" />
|
||||||
|
</intent-filter>
|
||||||
|
<intent-filter android:autoVerify="true">
|
||||||
|
<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" />
|
||||||
|
<data android:host="bookwyrm.spaceling.sh" />
|
||||||
|
</intent-filter>
|
||||||
|
<intent-filter android:autoVerify="true">
|
||||||
|
<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" />
|
||||||
|
<data android:host="lire.boitam.eu" />
|
||||||
|
</intent-filter>
|
||||||
|
<intent-filter android:autoVerify="true">
|
||||||
|
<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" />
|
||||||
|
<data android:host="kirja.casa" />
|
||||||
|
</intent-filter>
|
||||||
|
<intent-filter android:autoVerify="true">
|
||||||
|
<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" />
|
||||||
|
<data android:host="books.badwolfbay.games" />
|
||||||
|
</intent-filter>
|
||||||
|
<intent-filter android:autoVerify="true">
|
||||||
|
<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" />
|
||||||
|
<data android:host="books.unexist.dev" />
|
||||||
|
</intent-filter>
|
||||||
|
<intent-filter android:autoVerify="true">
|
||||||
|
<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" />
|
||||||
|
<data android:host="bookwyrm.cincodenada.com" />
|
||||||
|
</intent-filter>
|
||||||
|
<intent-filter android:autoVerify="true">
|
||||||
|
<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" />
|
||||||
|
<data android:host="books.underscore.world" />
|
||||||
|
</intent-filter>
|
||||||
|
<intent-filter android:autoVerify="true">
|
||||||
|
<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" />
|
||||||
|
<data android:host="bookwyrm.tardis.pw" />
|
||||||
|
</intent-filter>
|
||||||
|
<intent-filter android:autoVerify="true">
|
||||||
|
<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" />
|
||||||
|
<data android:host="masstoc.io" />
|
||||||
|
</intent-filter>
|
||||||
|
<intent-filter android:autoVerify="true">
|
||||||
|
<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" />
|
||||||
|
<data android:host="tankie.ml" />
|
||||||
|
</intent-filter>
|
||||||
|
<intent-filter android:autoVerify="true">
|
||||||
|
<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" />
|
||||||
|
<data android:host="books.mennisch.net" />
|
||||||
|
</intent-filter>
|
||||||
|
<intent-filter android:autoVerify="true">
|
||||||
|
<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" />
|
||||||
|
<data android:host="bookwyrm.pt" />
|
||||||
|
</intent-filter>
|
||||||
|
<intent-filter android:autoVerify="true">
|
||||||
|
<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" />
|
||||||
|
<data android:host="bookwyrm.lond.com.br" />
|
||||||
|
</intent-filter>
|
||||||
|
<intent-filter android:autoVerify="true">
|
||||||
|
<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" />
|
||||||
|
<data android:host="good.franv.site" />
|
||||||
|
</intent-filter>
|
||||||
|
<intent-filter android:autoVerify="true">
|
||||||
|
<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" />
|
||||||
|
<data android:host="books.solarpunkanarchism.org" />
|
||||||
|
</intent-filter>
|
||||||
|
<intent-filter android:autoVerify="true">
|
||||||
|
<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" />
|
||||||
|
<data android:host="shoko.one" />
|
||||||
|
</intent-filter>
|
||||||
|
<intent-filter android:autoVerify="true">
|
||||||
|
<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" />
|
||||||
|
<data android:host="bookwyrm.mennisch.net" />
|
||||||
|
</intent-filter>
|
||||||
|
<intent-filter android:autoVerify="true">
|
||||||
|
<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" />
|
||||||
|
<data android:host="bookrastinating.com" />
|
||||||
|
</intent-filter>
|
||||||
|
<intent-filter android:autoVerify="true">
|
||||||
|
<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" />
|
||||||
|
<data android:host="library.cybre.city" />
|
||||||
|
</intent-filter>
|
||||||
|
<intent-filter android:autoVerify="true">
|
||||||
|
<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" />
|
||||||
|
<data android:host="books.storydragon.nl" />
|
||||||
|
</intent-filter>
|
||||||
|
<intent-filter android:autoVerify="true">
|
||||||
|
<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" />
|
||||||
|
<data android:host="reading.unbl.ink" />
|
||||||
|
</intent-filter>
|
||||||
|
<intent-filter android:autoVerify="true">
|
||||||
|
<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" />
|
||||||
|
<data android:host="velhaestante.com.br" />
|
||||||
|
</intent-filter>
|
||||||
|
<intent-filter android:autoVerify="true">
|
||||||
|
<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" />
|
||||||
|
<data android:host="bookwyrm.gatti.ninja" />
|
||||||
|
</intent-filter>
|
||||||
|
<intent-filter android:autoVerify="true">
|
||||||
|
<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" />
|
||||||
|
<data android:host="books.theunseen.city" />
|
||||||
|
</intent-filter>
|
||||||
|
<intent-filter android:autoVerify="true">
|
||||||
|
<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" />
|
||||||
|
<data android:host="lore.livellosegreto.it" />
|
||||||
|
</intent-filter>
|
||||||
|
<intent-filter android:autoVerify="true">
|
||||||
|
<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" />
|
||||||
|
<data android:host="books.jascha.wtf" />
|
||||||
|
</intent-filter>
|
||||||
|
<intent-filter android:autoVerify="true">
|
||||||
|
<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" />
|
||||||
|
<data android:host="bw.diaspodon.fr" />
|
||||||
|
</intent-filter>
|
||||||
|
<intent-filter android:autoVerify="true">
|
||||||
|
<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" />
|
||||||
|
<data android:host="bookwyrm.tilde.zone" />
|
||||||
|
</intent-filter>
|
||||||
|
<intent-filter android:autoVerify="true">
|
||||||
|
<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" />
|
||||||
|
<data android:host="libros.mistli.net" />
|
||||||
|
</intent-filter>
|
||||||
|
<intent-filter android:autoVerify="true">
|
||||||
|
<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" />
|
||||||
|
<data android:host="orreadi.com" />
|
||||||
|
</intent-filter>
|
||||||
|
<intent-filter android:autoVerify="true">
|
||||||
|
<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" />
|
||||||
|
<data android:host="lectura.social" />
|
||||||
|
</intent-filter>
|
||||||
|
<intent-filter android:autoVerify="true">
|
||||||
|
<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" />
|
||||||
|
<data android:host="bookishbook.club" />
|
||||||
|
</intent-filter>
|
||||||
|
<intent-filter android:autoVerify="true">
|
||||||
|
<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" />
|
||||||
|
<data android:host="bookwyrm.tech" />
|
||||||
|
</intent-filter>
|
||||||
|
<intent-filter android:autoVerify="true">
|
||||||
|
<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" />
|
||||||
|
<data android:host="comelibros.club" />
|
||||||
|
</intent-filter>
|
||||||
|
<intent-filter android:autoVerify="true">
|
||||||
|
<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" />
|
||||||
|
<data android:host="ramblingreaders.org" />
|
||||||
|
</intent-filter>
|
||||||
|
<intent-filter android:autoVerify="true">
|
||||||
|
<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" />
|
||||||
|
<data android:host="secretbearlibrary.org" />
|
||||||
|
</intent-filter>
|
||||||
|
<intent-filter android:autoVerify="true">
|
||||||
|
<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" />
|
||||||
|
<data android:host="grimoire.party" />
|
||||||
|
</intent-filter>
|
||||||
|
<intent-filter android:autoVerify="true">
|
||||||
|
<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" />
|
||||||
|
<data android:host="biblio.thekambattu.rocks" />
|
||||||
|
</intent-filter>
|
||||||
|
<intent-filter android:autoVerify="true">
|
||||||
|
<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" />
|
||||||
|
<data android:host="buecher.pnpde.social" />
|
||||||
|
</intent-filter>
|
||||||
|
<intent-filter android:autoVerify="true">
|
||||||
|
<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" />
|
||||||
|
<data android:host="bouquins.zbeul.fr" />
|
||||||
|
</intent-filter>
|
||||||
|
<intent-filter android:autoVerify="true">
|
||||||
|
<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" />
|
||||||
|
<data android:host="boundcovers.com" />
|
||||||
|
</intent-filter>
|
||||||
|
<intent-filter android:autoVerify="true">
|
||||||
|
<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" />
|
||||||
|
<data android:host="tomes.tchncs.de" />
|
||||||
|
</intent-filter>
|
||||||
|
<intent-filter android:autoVerify="true">
|
||||||
|
<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" />
|
||||||
|
<data android:host="bw.heraut.eu" />
|
||||||
|
</intent-filter>
|
||||||
|
<intent-filter android:autoVerify="true">
|
||||||
|
<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" />
|
||||||
|
<data android:host="bookwyrm.welhaba.mx" />
|
||||||
|
</intent-filter>
|
||||||
|
<intent-filter android:autoVerify="true">
|
||||||
|
<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" />
|
||||||
|
<data android:host="books.regenpfeifer.net" />
|
||||||
|
</intent-filter>
|
||||||
|
<intent-filter android:autoVerify="true">
|
||||||
|
<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" />
|
||||||
|
<data android:host="libroj.org" />
|
||||||
|
</intent-filter>
|
||||||
|
<intent-filter android:autoVerify="true">
|
||||||
|
<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" />
|
||||||
|
<data android:host="bookshelf.hutchie.scot" />
|
||||||
|
</intent-filter>
|
||||||
|
<intent-filter android:autoVerify="true">
|
||||||
|
<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" />
|
||||||
|
<data android:host="b.skobk.in" />
|
||||||
|
</intent-filter>
|
||||||
|
<intent-filter android:autoVerify="true">
|
||||||
|
<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" />
|
||||||
|
<data android:host="outside.ofa.dog" />
|
||||||
|
</intent-filter>
|
||||||
|
<intent-filter android:autoVerify="true">
|
||||||
|
<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" />
|
||||||
|
<data android:host="books.babb.no" />
|
||||||
|
</intent-filter>
|
||||||
|
<intent-filter android:autoVerify="true">
|
||||||
|
<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" />
|
||||||
|
<data android:host="millefeuilles.cloud" />
|
||||||
|
</intent-filter>
|
||||||
|
<intent-filter android:autoVerify="true">
|
||||||
|
<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" />
|
||||||
|
<data android:host="grimoire.social" />
|
||||||
|
</intent-filter>
|
||||||
|
<intent-filter android:autoVerify="true">
|
||||||
|
<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" />
|
||||||
|
<data android:host="bookwyrm.it" />
|
||||||
|
</intent-filter>
|
||||||
|
<intent-filter android:autoVerify="true">
|
||||||
|
<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" />
|
||||||
|
<data android:host="books.chriswb.dev" />
|
||||||
|
</intent-filter>
|
||||||
|
<intent-filter android:autoVerify="true">
|
||||||
|
<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" />
|
||||||
|
<data android:host="leselog.de" />
|
||||||
|
</intent-filter>
|
||||||
|
<intent-filter android:autoVerify="true">
|
||||||
|
<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" />
|
||||||
|
<data android:host="reads.netsphere.pub" />
|
||||||
|
</intent-filter>
|
||||||
|
<intent-filter android:autoVerify="true">
|
||||||
|
<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" />
|
||||||
|
<data android:host="bookwyrm.world" />
|
||||||
|
</intent-filter>
|
||||||
|
<intent-filter android:autoVerify="true">
|
||||||
|
<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" />
|
||||||
|
<data android:host="reads.caskey-demaret.se" />
|
||||||
|
</intent-filter>
|
||||||
|
<intent-filter android:autoVerify="true">
|
||||||
|
<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" />
|
||||||
|
<data android:host="library.southfox.me" />
|
||||||
|
</intent-filter>
|
||||||
|
<intent-filter android:autoVerify="true">
|
||||||
|
<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" />
|
||||||
|
<data android:host="wyrm.maraval.net" />
|
||||||
|
</intent-filter>
|
||||||
|
<intent-filter android:autoVerify="true">
|
||||||
|
<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" />
|
||||||
|
<data android:host="sfba.club" />
|
||||||
|
</intent-filter>
|
||||||
|
<intent-filter android:autoVerify="true">
|
||||||
|
<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" />
|
||||||
|
<data android:host="linguistic.earth" />
|
||||||
|
</intent-filter>
|
||||||
|
<intent-filter android:autoVerify="true">
|
||||||
|
<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" />
|
||||||
|
<data android:host="wyrmsign.org" />
|
||||||
|
</intent-filter>
|
||||||
|
<intent-filter android:autoVerify="true">
|
||||||
|
<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" />
|
||||||
|
<data android:host="book.dadalo.pl" />
|
||||||
|
</intent-filter>
|
||||||
|
<intent-filter android:autoVerify="true">
|
||||||
|
<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" />
|
||||||
|
<data android:host="books.bimbiribase.xyz" />
|
||||||
|
</intent-filter>
|
||||||
|
<intent-filter android:autoVerify="true">
|
||||||
|
<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" />
|
||||||
|
<data android:host="bolha.review" />
|
||||||
|
</intent-filter>
|
||||||
|
<intent-filter android:autoVerify="true">
|
||||||
|
<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" />
|
||||||
|
<data android:host="plaerdemavida.cat" />
|
||||||
|
</intent-filter>
|
||||||
|
<intent-filter android:autoVerify="true">
|
||||||
|
<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" />
|
||||||
|
<data android:host="paperjale.eus" />
|
||||||
|
</intent-filter>
|
||||||
|
<intent-filter android:autoVerify="true">
|
||||||
|
<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" />
|
||||||
|
<data android:host="books.duck.cafe" />
|
||||||
|
</intent-filter>
|
||||||
|
<intent-filter android:autoVerify="true">
|
||||||
|
<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" />
|
||||||
|
<data android:host="books.hccp.org" />
|
||||||
|
</intent-filter>
|
||||||
|
<intent-filter android:autoVerify="true">
|
||||||
|
<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" />
|
||||||
|
<data android:host="library.chatan.cc" />
|
||||||
|
</intent-filter>
|
||||||
|
<intent-filter android:autoVerify="true">
|
||||||
|
<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" />
|
||||||
|
<data android:host="knowledgehub.social" />
|
||||||
|
</intent-filter>
|
||||||
|
<intent-filter android:autoVerify="true">
|
||||||
|
<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" />
|
||||||
|
<data android:host="alexandria.the1977project.org" />
|
||||||
|
</intent-filter>
|
||||||
|
</activity>
|
||||||
<activity
|
<activity
|
||||||
android:name=".StartActivity"
|
android:name=".StartActivity"
|
||||||
android:exported="false" />
|
android:exported="false" />
|
||||||
|
364
app/src/main/java/nl/privacydragon/bookwyrm/HandlerActivity.java
Normal file
364
app/src/main/java/nl/privacydragon/bookwyrm/HandlerActivity.java
Normal file
@ -0,0 +1,364 @@
|
|||||||
|
package nl.privacydragon.bookwyrm;
|
||||||
|
|
||||||
|
import android.Manifest;
|
||||||
|
import android.annotation.SuppressLint;
|
||||||
|
import android.app.Activity;
|
||||||
|
import android.content.ActivityNotFoundException;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.content.SharedPreferences;
|
||||||
|
import android.content.pm.PackageManager;
|
||||||
|
import android.graphics.Bitmap;
|
||||||
|
import android.net.Uri;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.util.Base64;
|
||||||
|
import android.view.KeyEvent;
|
||||||
|
import android.view.View;
|
||||||
|
import android.webkit.JavascriptInterface;
|
||||||
|
import android.webkit.ValueCallback;
|
||||||
|
import android.webkit.WebChromeClient;
|
||||||
|
import android.webkit.WebResourceRequest;
|
||||||
|
import android.webkit.WebView;
|
||||||
|
import android.webkit.WebViewClient;
|
||||||
|
import android.widget.ProgressBar;
|
||||||
|
import android.widget.Toast;
|
||||||
|
|
||||||
|
import androidx.activity.result.ActivityResultLauncher;
|
||||||
|
import androidx.activity.result.contract.ActivityResultContracts;
|
||||||
|
import androidx.appcompat.app.AppCompatActivity;
|
||||||
|
import androidx.core.app.ActivityCompat;
|
||||||
|
import androidx.core.content.ContextCompat;
|
||||||
|
|
||||||
|
import com.journeyapps.barcodescanner.ScanContract;
|
||||||
|
import com.journeyapps.barcodescanner.ScanOptions;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.security.InvalidAlgorithmParameterException;
|
||||||
|
import java.security.InvalidKeyException;
|
||||||
|
import java.security.Key;
|
||||||
|
import java.security.KeyStore;
|
||||||
|
import java.security.KeyStoreException;
|
||||||
|
import java.security.NoSuchAlgorithmException;
|
||||||
|
import java.security.UnrecoverableKeyException;
|
||||||
|
import java.security.cert.CertificateException;
|
||||||
|
|
||||||
|
import javax.crypto.BadPaddingException;
|
||||||
|
import javax.crypto.Cipher;
|
||||||
|
import javax.crypto.IllegalBlockSizeException;
|
||||||
|
import javax.crypto.NoSuchPaddingException;
|
||||||
|
import javax.crypto.spec.GCMParameterSpec;
|
||||||
|
|
||||||
|
public class HandlerActivity extends AppCompatActivity {
|
||||||
|
|
||||||
|
WebView myWebView;
|
||||||
|
ProgressBar LoadIndicator;
|
||||||
|
public ValueCallback<Uri[]> omhooglader;
|
||||||
|
@SuppressLint("SetJavaScriptEnabled")
|
||||||
|
@Override
|
||||||
|
protected void onCreate(Bundle savedInstanceState) {
|
||||||
|
super.onCreate(savedInstanceState);
|
||||||
|
setContentView(R.layout.activity_start);
|
||||||
|
// 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
|
||||||
|
ActivityResultLauncher<Intent> voodooLauncher = registerForActivityResult(
|
||||||
|
new ActivityResultContracts.StartActivityForResult(),
|
||||||
|
result -> {
|
||||||
|
if (result.getResultCode() == Activity.RESULT_OK) {
|
||||||
|
// There are no request codes
|
||||||
|
Intent data = result.getData();
|
||||||
|
if (omhooglader == null)
|
||||||
|
return;
|
||||||
|
omhooglader.onReceiveValue(WebChromeClient.FileChooserParams.parseResult(result.getResultCode(), data));
|
||||||
|
} else {
|
||||||
|
omhooglader.onReceiveValue(null);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
LoadIndicator = (ProgressBar) findViewById(R.id.progressBar3);
|
||||||
|
myWebView = (WebView) findViewById(R.id.webview);
|
||||||
|
myWebView.setVisibility(View.GONE);
|
||||||
|
myWebView.getSettings().setJavaScriptEnabled(true);
|
||||||
|
myWebView.getSettings().setDomStorageEnabled(true);
|
||||||
|
myWebView.getSettings().setAllowFileAccess(true);
|
||||||
|
myWebView.getSettings().setAllowContentAccess(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.setWebChromeClient(new WebChromeClient() {
|
||||||
|
@Override
|
||||||
|
public boolean onShowFileChooser(WebView webView, ValueCallback<Uri[]> filePathCallback, FileChooserParams fileChooserParams) {
|
||||||
|
if (omhooglader != null) {
|
||||||
|
//omhooglader.onReceiveValue(null);
|
||||||
|
omhooglader = null;
|
||||||
|
}
|
||||||
|
omhooglader = filePathCallback;
|
||||||
|
Intent intent = fileChooserParams.createIntent();
|
||||||
|
try {
|
||||||
|
voodooLauncher.launch(intent);
|
||||||
|
} catch (ActivityNotFoundException grrr){
|
||||||
|
omhooglader = null;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
//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.
|
||||||
|
String defaultValue = "none";
|
||||||
|
SharedPreferences sharedPref = HandlerActivity.this.getSharedPreferences(getString(R.string.server), Context.MODE_PRIVATE);
|
||||||
|
String server = sharedPref.getString(getString(R.string.server), defaultValue);
|
||||||
|
SharedPreferences sharedPrefName = HandlerActivity.this.getSharedPreferences(getString(R.string.name), Context.MODE_PRIVATE);
|
||||||
|
String name = sharedPrefName.getString(getString(R.string.name), defaultValue);
|
||||||
|
SharedPreferences sharedPrefPass = HandlerActivity.this.getSharedPreferences(getString(R.string.pw), Context.MODE_PRIVATE);
|
||||||
|
String pass = sharedPrefPass.getString(getString(R.string.pw), defaultValue);
|
||||||
|
SharedPreferences sharedPrefMagic = HandlerActivity.this.getSharedPreferences(getString(R.string.q), Context.MODE_PRIVATE);
|
||||||
|
String codeMagic = sharedPrefMagic.getString(getString(R.string.q), defaultValue);
|
||||||
|
//If there is nothing configured yet, the user should be redirected to the main screen for logging in.
|
||||||
|
if (server == "none") {
|
||||||
|
startActivity(new Intent(HandlerActivity.this, nl.privacydragon.bookwyrm.MainActivity.class));
|
||||||
|
}
|
||||||
|
String pathMaybe = appLinkData.getPath();
|
||||||
|
String toGoServer = "bla";
|
||||||
|
//This bit of code regelt wanneer de webpagina wordt weergegeven. It is quite handig then om dan ook "book" toe te laten, zodat ook boeken in de app bekeken kunnen worden...
|
||||||
|
if (pathMaybe.contains("user") || pathMaybe.contains("book")) {
|
||||||
|
//If the path contains 'user', it is a user profile, unless it is followed by something like 'review'.
|
||||||
|
if (pathMaybe.contains("review") || pathMaybe.contains("generatednote") || pathMaybe.contains("quotation") || pathMaybe.contains("comment") || pathMaybe.contains("book")) {
|
||||||
|
toGoServer = "https://" + appLinkData.getHost() + pathMaybe;
|
||||||
|
}
|
||||||
|
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 {
|
||||||
|
//If the toGoServer string remains "bla", dan zal de user when they teruggaan uitkomen op https://bla/, which is 'not allowed'.
|
||||||
|
//So, maybe here, just to be sure, assign the value of the user's own server to the toGoServer variabele.
|
||||||
|
//After that, since apparently I have decided that the URL the user tried to follow is not valid in my application, redirect them to StartActivity.
|
||||||
|
toGoServer = "https://" + server;
|
||||||
|
startActivity(new Intent(HandlerActivity.this, nl.privacydragon.bookwyrm.StartActivity.class));
|
||||||
|
}
|
||||||
|
//Then all the decryption stuff has to happen. There are a lot of try-catch stuff, because apparently that seems to be needed.
|
||||||
|
//First get the keystore thing.
|
||||||
|
KeyStore keyStore = null;
|
||||||
|
try {
|
||||||
|
keyStore = KeyStore.getInstance("AndroidKeyStore");
|
||||||
|
} catch (KeyStoreException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
//Then, load it. or something. To make sure that it can be used.
|
||||||
|
try {
|
||||||
|
keyStore.load(null);
|
||||||
|
} catch (CertificateException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
} catch (NoSuchAlgorithmException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
//Next, retrieve the key to be used for the decryption.
|
||||||
|
Key DragonLikeKey = null;
|
||||||
|
try {
|
||||||
|
DragonLikeKey = keyStore.getKey("BookWyrm", null);
|
||||||
|
} catch (KeyStoreException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
} catch (NoSuchAlgorithmException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
} catch (UnrecoverableKeyException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
//Do something with getting the/a cipher or something.
|
||||||
|
Cipher c = null;
|
||||||
|
try {
|
||||||
|
c = Cipher.getInstance("AES/GCM/NoPadding");
|
||||||
|
} catch (NoSuchAlgorithmException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
} catch (NoSuchPaddingException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
//And then initiating the cipher, so it can be used.
|
||||||
|
try {
|
||||||
|
c.init(Cipher.DECRYPT_MODE, DragonLikeKey, new GCMParameterSpec(128, codeMagic.getBytes()));
|
||||||
|
} catch (InvalidAlgorithmParameterException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
} catch (InvalidKeyException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
//Decrypt the password!
|
||||||
|
byte[] truePass = null;
|
||||||
|
try {
|
||||||
|
truePass = c.doFinal(Base64.decode(pass, Base64.DEFAULT));
|
||||||
|
} catch (BadPaddingException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
} catch (IllegalBlockSizeException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
//Convert the decrypted password back to a string.
|
||||||
|
String passw = new String(truePass, StandardCharsets.UTF_8);
|
||||||
|
|
||||||
|
//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.
|
||||||
|
String finalToGoServer = toGoServer;
|
||||||
|
myWebView.setWebViewClient(new HandlerActivity.MyWebViewClient() {
|
||||||
|
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_localname').value = '" + name + "'; ;})()");
|
||||||
|
view.loadUrl("javascript:(function() { if (window.location.href == '" + finalToGoServer + "' && !/(review|generatednote|quotation|comment|book)/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|book)/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.
|
||||||
|
myWebView.loadUrl(toGoServer);
|
||||||
|
}
|
||||||
|
|
||||||
|
private final ActivityResultLauncher<ScanOptions> barcodeLanceerder = registerForActivityResult(new ScanContract(),
|
||||||
|
result -> {
|
||||||
|
if(result.getContents() == null) {
|
||||||
|
Toast.makeText(HandlerActivity.this, "Cancelled", Toast.LENGTH_LONG).show();
|
||||||
|
} else {
|
||||||
|
Toast.makeText(HandlerActivity.this, "Scanned: " + result.getContents(), Toast.LENGTH_LONG).show();
|
||||||
|
myWebView.loadUrl("Javascript:(function() {" +
|
||||||
|
"try {" +
|
||||||
|
"document.getElementById('tour-search').value = " + result.getContents() + ";" +
|
||||||
|
"} catch {" +
|
||||||
|
"document.getElementById('search_input').value = " + result.getContents() + ";" +
|
||||||
|
"}" +
|
||||||
|
"document.getElementsByTagName('form')[0].submit();" +
|
||||||
|
";})()");
|
||||||
|
LoadIndicator.setVisibility(View.VISIBLE);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
ScanOptions eisen = new ScanOptions();
|
||||||
|
eisen.setDesiredBarcodeFormats(ScanOptions.EAN_13);
|
||||||
|
eisen.setBeepEnabled(true);
|
||||||
|
eisen.setCameraId(0);
|
||||||
|
eisen.setPrompt("SCAN ISBN");
|
||||||
|
eisen.setBarcodeImageEnabled(false);
|
||||||
|
barcodeLanceerder.launch(eisen);
|
||||||
|
//return "blup";
|
||||||
|
//return "bla";
|
||||||
|
}
|
||||||
|
|
||||||
|
@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);
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public boolean onKeyLongPress(int keyCode, KeyEvent event) {
|
||||||
|
if (keyCode == KeyEvent.KEYCODE_BACK) {
|
||||||
|
finish();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return super.onKeyLongPress(keyCode, event);
|
||||||
|
}
|
||||||
|
//Here is code to make sure that links of the bookwyrm server are handled within the webview client, instead of having it open in the default browser.
|
||||||
|
//Yes, I used the web for this too.
|
||||||
|
private class MyWebViewClient extends WebViewClient {
|
||||||
|
@Override
|
||||||
|
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);
|
||||||
|
String defaultValue = "none";
|
||||||
|
String server = sharedPref.getString(getString(R.string.server), defaultValue);
|
||||||
|
if (server.equals(request.getUrl().getHost())) {
|
||||||
|
//If the server is the same as the bookwyrm, load it in the webview.
|
||||||
|
return false;
|
||||||
|
} else if (strangeHost.equals(request.getUrl().getHost())) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// Otherwise, it should go to the default browser instead.
|
||||||
|
Intent intent = new Intent(Intent.ACTION_VIEW, request.getUrl());
|
||||||
|
startActivity(intent);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onPageStarted(WebView view, String url, Bitmap favicon) {
|
||||||
|
LoadIndicator.setVisibility(View.VISIBLE);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
@ -4,52 +4,118 @@ import android.content.Context;
|
|||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.content.SharedPreferences;
|
import android.content.SharedPreferences;
|
||||||
import android.graphics.Color;
|
import android.graphics.Color;
|
||||||
import android.support.v7.app.AppCompatActivity;
|
import android.security.keystore.KeyGenParameterSpec;
|
||||||
|
import android.security.keystore.KeyProperties;
|
||||||
|
//import android.support.v7.app.AppCompatActivity;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
|
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.security.InvalidAlgorithmParameterException;
|
||||||
|
import java.security.InvalidKeyException;
|
||||||
|
import java.security.Key;
|
||||||
|
import java.security.KeyStore;
|
||||||
|
import java.security.KeyStoreException;
|
||||||
|
import java.security.NoSuchAlgorithmException;
|
||||||
|
import java.security.NoSuchProviderException;
|
||||||
|
import java.security.UnrecoverableKeyException;
|
||||||
|
import java.security.cert.CertificateException;
|
||||||
|
import java.util.Random;
|
||||||
|
|
||||||
|
import javax.crypto.BadPaddingException;
|
||||||
|
import javax.crypto.Cipher;
|
||||||
|
import javax.crypto.IllegalBlockSizeException;
|
||||||
|
import javax.crypto.KeyGenerator;
|
||||||
|
import javax.crypto.NoSuchPaddingException;
|
||||||
|
import javax.crypto.spec.GCMParameterSpec;
|
||||||
|
|
||||||
public class MainActivity extends AppCompatActivity {
|
public class MainActivity extends AppCompatActivity {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onCreate(Bundle savedInstanceState) {
|
protected void onCreate(Bundle savedInstanceState) {
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
setContentView(R.layout.activity_main);
|
setContentView(R.layout.activity_main);
|
||||||
//Context context = getActivity();
|
//Check whether there is something stored. Only if there is already something stored, proceed to BookWyrm.
|
||||||
SharedPreferences sharedPref = MainActivity.this.getSharedPreferences(getString(R.string.server), Context.MODE_PRIVATE);
|
SharedPreferences sharedPref = MainActivity.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 != "none") {
|
if (!"none".equals(server)) {
|
||||||
startActivity(new Intent(MainActivity.this, nl.privacydragon.bookwyrm.StartActivity.class));
|
startActivity(new Intent(MainActivity.this, nl.privacydragon.bookwyrm.StartActivity.class));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static String getRandomString() //I just copied this from internet. Yes, I am lazy :). (https://stackoverflow.com/questions/12116092/android-random-string-generator#answer-12116194)
|
||||||
|
{
|
||||||
|
String ALLOWED_CHARACTERS ="0123456789qwertyuiopasdfghjklzxcvbnm!@#$%^&*()_+=][{}";
|
||||||
|
final Random random=new Random();
|
||||||
|
final StringBuilder sb=new StringBuilder(12);
|
||||||
|
for(int i = 0; i< 12; ++i) {
|
||||||
|
sb.append(ALLOWED_CHARACTERS.charAt(random.nextInt(ALLOWED_CHARACTERS.length())));
|
||||||
|
}
|
||||||
|
return sb.toString();
|
||||||
|
}
|
||||||
|
|
||||||
public void LogIn(View view) {
|
public void LogIn(View view) throws IllegalBlockSizeException, BadPaddingException, KeyStoreException, CertificateException, IOException, NoSuchAlgorithmException, NoSuchProviderException, InvalidAlgorithmParameterException, UnrecoverableKeyException, NoSuchPaddingException, InvalidKeyException {
|
||||||
|
//Declaring some things needed. Getting the user input.
|
||||||
EditText serverInput = (EditText) findViewById(R.id.Instance);
|
EditText serverInput = (EditText) findViewById(R.id.Instance);
|
||||||
String server = String.valueOf(serverInput.getText());
|
String server = String.valueOf(serverInput.getText());
|
||||||
EditText passInput = (EditText) findViewById(R.id.Password);
|
EditText passInput = (EditText) findViewById(R.id.Password);
|
||||||
String pass = String.valueOf(passInput.getText());
|
String pass = String.valueOf(passInput.getText());
|
||||||
EditText nameInput = (EditText) findViewById(R.id.Username);
|
EditText nameInput = (EditText) findViewById(R.id.Username);
|
||||||
String name = String.valueOf(nameInput.getText());
|
String name = String.valueOf(nameInput.getText());
|
||||||
|
//All fields are required, so if one of them is empty, the user should see a warning.
|
||||||
if (server.isEmpty() || pass.isEmpty() || name.isEmpty()) {
|
if (server.isEmpty() || pass.isEmpty() || name.isEmpty()) {
|
||||||
TextView ErrorMessage = (TextView) findViewById(R.id.textView5);
|
TextView ErrorMessage = (TextView) findViewById(R.id.textView5);
|
||||||
ErrorMessage.setTextColor(Color.RED);
|
ErrorMessage.setTextColor(Color.RED);
|
||||||
ErrorMessage.setText("ERROR: All fields are required!");
|
ErrorMessage.setText("ERROR: All fields are required!");
|
||||||
} else {
|
} else {
|
||||||
|
//Likely this will be the first time the program is run. So create a new key thing in the android key store happening.
|
||||||
|
KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore");
|
||||||
|
keyStore.load(null);
|
||||||
|
if (!keyStore.containsAlias("BookWyrm")) { //Actually, the new key is made here, if it does not exist already.
|
||||||
|
KeyGenerator keyGenerator = KeyGenerator.getInstance(KeyProperties.KEY_ALGORITHM_AES, "AndroidKeyStore");
|
||||||
|
keyGenerator.init(
|
||||||
|
new KeyGenParameterSpec.Builder("BookWyrm",
|
||||||
|
KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_DECRYPT)
|
||||||
|
.setBlockModes(KeyProperties.BLOCK_MODE_GCM).setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE)
|
||||||
|
.setRandomizedEncryptionRequired(false)
|
||||||
|
.build());
|
||||||
|
keyGenerator.generateKey();
|
||||||
|
}
|
||||||
|
//Grab the key and initiate the encryption process stuff. For this, a random fixed IV code is generated.
|
||||||
|
Key DragonLikeKey = keyStore.getKey("BookWyrm", null);
|
||||||
|
Cipher c = Cipher.getInstance("AES/GCM/NoPadding");
|
||||||
|
String magicCode = getRandomString();
|
||||||
|
c.init(Cipher.ENCRYPT_MODE, DragonLikeKey, new GCMParameterSpec(128, magicCode.getBytes()));
|
||||||
|
//And now do the encryption!
|
||||||
|
byte[] passBytes = c.doFinal(pass.getBytes());
|
||||||
|
String passUse = Base64.encodeToString(passBytes, Base64.DEFAULT);
|
||||||
|
//And then all the things are stored in the shared preferences.
|
||||||
|
//Therefore, first all the shared preferences objects are loaded.
|
||||||
SharedPreferences sharedPref = MainActivity.this.getSharedPreferences(getString(R.string.server), Context.MODE_PRIVATE);
|
SharedPreferences sharedPref = MainActivity.this.getSharedPreferences(getString(R.string.server), Context.MODE_PRIVATE);
|
||||||
SharedPreferences sharedPrefName = MainActivity.this.getSharedPreferences(getString(R.string.name), Context.MODE_PRIVATE);
|
SharedPreferences sharedPrefName = MainActivity.this.getSharedPreferences(getString(R.string.name), Context.MODE_PRIVATE);
|
||||||
SharedPreferences sharedPrefPass = MainActivity.this.getSharedPreferences(getString(R.string.pw), Context.MODE_PRIVATE);
|
SharedPreferences sharedPrefPass = MainActivity.this.getSharedPreferences(getString(R.string.pw), Context.MODE_PRIVATE);
|
||||||
|
SharedPreferences sharedPrefMagic = MainActivity.this.getSharedPreferences(getString(R.string.q), Context.MODE_PRIVATE);
|
||||||
|
//Then the 'edit' stuff are made for them.
|
||||||
SharedPreferences.Editor editorName = sharedPrefName.edit();
|
SharedPreferences.Editor editorName = sharedPrefName.edit();
|
||||||
SharedPreferences.Editor editorPass = sharedPrefPass.edit();
|
SharedPreferences.Editor editorPass = sharedPrefPass.edit();
|
||||||
|
SharedPreferences.Editor editorMagic = sharedPrefMagic.edit();
|
||||||
SharedPreferences.Editor editor = sharedPref.edit();
|
SharedPreferences.Editor editor = sharedPref.edit();
|
||||||
|
//And finally, the values are written to them.
|
||||||
editor.putString(getString(R.string.server), server);
|
editor.putString(getString(R.string.server), server);
|
||||||
editor.apply();
|
editor.apply();
|
||||||
editorName.putString(getString(R.string.name), name);
|
editorName.putString(getString(R.string.name), name);
|
||||||
editorName.apply();
|
editorName.apply();
|
||||||
editorPass.putString(getString(R.string.pw), pass);
|
editorPass.putString(getString(R.string.pw), passUse);
|
||||||
editorPass.apply();
|
editorPass.apply();
|
||||||
|
editorMagic.putString(getString(R.string.q), magicCode);
|
||||||
|
editorMagic.apply();
|
||||||
|
//Once all that has been done, Bookwyrm can be opened and such!
|
||||||
startActivity(new Intent(MainActivity.this, nl.privacydragon.bookwyrm.StartActivity.class));
|
startActivity(new Intent(MainActivity.this, nl.privacydragon.bookwyrm.StartActivity.class));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,49 +1,262 @@
|
|||||||
package nl.privacydragon.bookwyrm;
|
package nl.privacydragon.bookwyrm;
|
||||||
|
|
||||||
|
import android.Manifest;
|
||||||
import android.annotation.SuppressLint;
|
import android.annotation.SuppressLint;
|
||||||
|
import android.app.Activity;
|
||||||
|
import android.content.ActivityNotFoundException;
|
||||||
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.content.pm.PackageManager;
|
||||||
|
import android.graphics.Bitmap;
|
||||||
|
import android.net.Uri;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
|
import android.util.Base64;
|
||||||
|
import android.view.KeyEvent;
|
||||||
|
import android.view.View;
|
||||||
|
import android.webkit.JavascriptInterface;
|
||||||
|
import android.webkit.ValueCallback;
|
||||||
|
import android.webkit.WebChromeClient;
|
||||||
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.activity.result.ActivityResultLauncher;
|
||||||
|
import androidx.activity.result.contract.ActivityResultContracts;
|
||||||
|
import androidx.appcompat.app.AppCompatActivity;
|
||||||
|
import androidx.core.app.ActivityCompat;
|
||||||
|
import androidx.core.content.ContextCompat;
|
||||||
|
|
||||||
|
import com.journeyapps.barcodescanner.ScanContract;
|
||||||
|
import com.journeyapps.barcodescanner.ScanOptions;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.security.InvalidAlgorithmParameterException;
|
||||||
|
import java.security.InvalidKeyException;
|
||||||
|
import java.security.Key;
|
||||||
|
import java.security.KeyStore;
|
||||||
|
import java.security.KeyStoreException;
|
||||||
|
import java.security.NoSuchAlgorithmException;
|
||||||
|
import java.security.UnrecoverableKeyException;
|
||||||
|
import java.security.cert.CertificateException;
|
||||||
|
|
||||||
|
import javax.crypto.BadPaddingException;
|
||||||
|
import javax.crypto.Cipher;
|
||||||
|
import javax.crypto.IllegalBlockSizeException;
|
||||||
|
import javax.crypto.NoSuchPaddingException;
|
||||||
|
import javax.crypto.spec.GCMParameterSpec;
|
||||||
|
|
||||||
public class StartActivity extends AppCompatActivity {
|
public class StartActivity extends AppCompatActivity {
|
||||||
|
WebView myWebView;
|
||||||
|
ProgressBar LoadIndicator;
|
||||||
|
public ValueCallback<Uri[]> omhooglader;
|
||||||
@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);
|
||||||
|
ActivityResultLauncher<Intent> voodooLauncher = registerForActivityResult(
|
||||||
|
new ActivityResultContracts.StartActivityForResult(),
|
||||||
|
result -> {
|
||||||
|
if (result.getResultCode() == Activity.RESULT_OK) {
|
||||||
|
// There are no request codes
|
||||||
|
Intent data = result.getData();
|
||||||
|
if (omhooglader == null)
|
||||||
|
return;
|
||||||
|
omhooglader.onReceiveValue(WebChromeClient.FileChooserParams.parseResult(result.getResultCode(), data));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
omhooglader.onReceiveValue(null);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
myWebView = (WebView) findViewById(R.id.webview);
|
||||||
|
myWebView.setVisibility(View.GONE);
|
||||||
myWebView.getSettings().setJavaScriptEnabled(true);
|
myWebView.getSettings().setJavaScriptEnabled(true);
|
||||||
//Context context = StartActivity.this;
|
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.setWebChromeClient(new WebChromeClient() {
|
||||||
|
@Override
|
||||||
|
public boolean onShowFileChooser(WebView webView, ValueCallback<Uri[]> filePathCallback, FileChooserParams fileChooserParams) {
|
||||||
|
if (omhooglader != null) {
|
||||||
|
//omhooglader.onReceiveValue(null);
|
||||||
|
omhooglader = null;
|
||||||
|
}
|
||||||
|
omhooglader = filePathCallback;
|
||||||
|
Intent intent = fileChooserParams.createIntent();
|
||||||
|
try {
|
||||||
|
// String toestemming = Manifest.permission.READ_EXTERNAL_STORAGE;
|
||||||
|
// int grant = ContextCompat.checkSelfPermission(StartActivity.this, toestemming);
|
||||||
|
// if (grant != PackageManager.PERMISSION_GRANTED) {
|
||||||
|
// String[] permission_list = new String[1];
|
||||||
|
// permission_list[0] = toestemming;
|
||||||
|
// ActivityCompat.requestPermissions(StartActivity.this, permission_list, 1);
|
||||||
|
// }
|
||||||
|
voodooLauncher.launch(intent);
|
||||||
|
} catch (ActivityNotFoundException grrr){
|
||||||
|
omhooglader = null;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
//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);
|
||||||
String server = sharedPref.getString(getString(R.string.server), defaultValue);
|
String server = sharedPref.getString(getString(R.string.server), defaultValue);
|
||||||
SharedPreferences sharedPrefName = StartActivity.this.getSharedPreferences(getString(R.string.name), Context.MODE_PRIVATE);
|
SharedPreferences sharedPrefName = StartActivity.this.getSharedPreferences(getString(R.string.name), Context.MODE_PRIVATE);
|
||||||
String name = sharedPrefName.getString(getString(R.string.name), defaultValue);
|
String name = sharedPrefName.getString(getString(R.string.name), defaultValue);
|
||||||
SharedPreferences sharedPrefPass = StartActivity.this.getSharedPreferences(getString(R.string.pw), Context.MODE_PRIVATE);
|
SharedPreferences sharedPrefPass = StartActivity.this.getSharedPreferences(getString(R.string.pw), Context.MODE_PRIVATE);
|
||||||
String pass= sharedPrefPass.getString(getString(R.string.pw), defaultValue);
|
String pass = sharedPrefPass.getString(getString(R.string.pw), defaultValue);
|
||||||
|
SharedPreferences sharedPrefMagic = StartActivity.this.getSharedPreferences(getString(R.string.q), Context.MODE_PRIVATE);
|
||||||
|
String codeMagic = sharedPrefMagic.getString(getString(R.string.q), defaultValue);
|
||||||
|
//Then all the decryption stuff has to happen. There are a lot of try-catch stuff, because apparently that seems to be needed.
|
||||||
|
//First get the keystore thing.
|
||||||
|
KeyStore keyStore = null;
|
||||||
|
try {
|
||||||
|
keyStore = KeyStore.getInstance("AndroidKeyStore");
|
||||||
|
} catch (KeyStoreException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
//Then, load it. or something. To make sure that it can be used.
|
||||||
|
try {
|
||||||
|
keyStore.load(null);
|
||||||
|
} catch (CertificateException | IOException | NoSuchAlgorithmException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
//Next, retrieve the key to be used for the decryption.
|
||||||
|
Key DragonLikeKey = null;
|
||||||
|
try {
|
||||||
|
DragonLikeKey = keyStore.getKey("BookWyrm", null);
|
||||||
|
} catch (KeyStoreException | NoSuchAlgorithmException | UnrecoverableKeyException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
//Do something with getting the/a cipher or something.
|
||||||
|
Cipher c = null;
|
||||||
|
try {
|
||||||
|
c = Cipher.getInstance("AES/GCM/NoPadding");
|
||||||
|
} catch (NoSuchAlgorithmException | NoSuchPaddingException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
//And then initiating the cipher, so it can be used.
|
||||||
|
try {
|
||||||
|
assert c != null;
|
||||||
|
c.init(Cipher.DECRYPT_MODE, DragonLikeKey, new GCMParameterSpec(128, codeMagic.getBytes()));
|
||||||
|
} catch (InvalidAlgorithmParameterException | InvalidKeyException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
//Decrypt the password!
|
||||||
|
byte[] truePass = null;
|
||||||
|
try {
|
||||||
|
truePass = c.doFinal(Base64.decode(pass, Base64.DEFAULT));
|
||||||
|
} catch (BadPaddingException | IllegalBlockSizeException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
//Convert the decrypted password back to a string.
|
||||||
|
String passw = new String(truePass, StandardCharsets.UTF_8);
|
||||||
|
|
||||||
|
//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 = '" + pass + "'; ;})()");
|
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.
|
||||||
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
//String data = "localname="+name+"&password="+pass;
|
//Here, load the login page of the server. That actually does all that is needed.
|
||||||
//String data = "";
|
|
||||||
//myWebView.loadDataWithBaseURL("https://httpbin.org");
|
|
||||||
//myWebView.loadDataWithBaseURL("https://httpbin.org/", data, "", "", "");
|
|
||||||
//myWebView.postUrl("https://"+ server + "/login", EncodingUtils.getBytes(data, "base64"));
|
|
||||||
myWebView.loadUrl("https://" + server + "/login");
|
myWebView.loadUrl("https://" + server + "/login");
|
||||||
//myWebView.loadUrl("javascript:document.getElementsById('id_password_confirm').value = \""+pass+"\"");
|
|
||||||
}
|
}
|
||||||
|
private final ActivityResultLauncher<ScanOptions> barcodeLanceerder = registerForActivityResult(new ScanContract(),
|
||||||
|
result -> {
|
||||||
|
if(result.getContents() == null) {
|
||||||
|
Toast.makeText(StartActivity.this, "Cancelled", Toast.LENGTH_LONG).show();
|
||||||
|
} else {
|
||||||
|
Toast.makeText(StartActivity.this, "Scanned: " + result.getContents(), Toast.LENGTH_LONG).show();
|
||||||
|
myWebView.loadUrl("Javascript:(function() {" +
|
||||||
|
"try {" +
|
||||||
|
"document.getElementById('tour-search').value = " + result.getContents() + ";" +
|
||||||
|
"} catch {" +
|
||||||
|
"document.getElementById('search_input').value = " + result.getContents() + ";" +
|
||||||
|
"}" +
|
||||||
|
"document.getElementsByTagName('form')[0].submit();" +
|
||||||
|
";})()");
|
||||||
|
LoadIndicator.setVisibility(View.VISIBLE);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
ScanOptions eisen = new ScanOptions();
|
||||||
|
eisen.setDesiredBarcodeFormats(ScanOptions.EAN_13);
|
||||||
|
eisen.setBeepEnabled(true);
|
||||||
|
eisen.setCameraId(0);
|
||||||
|
eisen.setPrompt("SCAN ISBN");
|
||||||
|
eisen.setBarcodeImageEnabled(false);
|
||||||
|
barcodeLanceerder.launch(eisen);
|
||||||
|
//return "blup";
|
||||||
|
//return "bla";
|
||||||
|
}
|
||||||
|
|
||||||
|
@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);
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public boolean onKeyLongPress(int keyCode, KeyEvent event) {
|
||||||
|
if (keyCode == KeyEvent.KEYCODE_BACK) {
|
||||||
|
finish();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return super.onKeyLongPress(keyCode, event);
|
||||||
|
}
|
||||||
|
//Here is code to make sure that links of the bookwyrm server are handled within the webview client, instead of having it open in the default browser.
|
||||||
|
//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) {
|
||||||
@ -51,13 +264,18 @@ public class StartActivity extends AppCompatActivity {
|
|||||||
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())) {
|
||||||
// This is my website, so do not override; let my WebView load the page
|
//If the server is the same as the bookwyrm, load it in the webview.
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
// Otherwise, the link is not for a page on my site, so launch another Activity that handles URLs
|
// 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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -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>
|
@ -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>
|
|
@ -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>
|
||||||
|
@ -3,4 +3,5 @@
|
|||||||
<string name="server">bla</string>
|
<string name="server">bla</string>
|
||||||
<string name="name">blup</string>
|
<string name="name">blup</string>
|
||||||
<string name="pw">gloep</string>
|
<string name="pw">gloep</string>
|
||||||
|
<string name="q">wheeeee</string>
|
||||||
</resources>
|
</resources>
|
@ -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>
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
// Top-level build file where you can add configuration options common to all sub-projects/modules.
|
// Top-level build file where you can add configuration options common to all sub-projects/modules.
|
||||||
plugins {
|
plugins {
|
||||||
id 'com.android.application' version '7.1.1' apply false
|
id 'com.android.application' version '8.7.3' apply false
|
||||||
id 'com.android.library' version '7.1.1' apply false
|
id 'com.android.library' version '8.7.3' apply false
|
||||||
}
|
}
|
||||||
|
|
||||||
task clean(type: Delete) {
|
task clean(type: Delete) {
|
||||||
|
3
fastlane/metadata/android/en-US/changelogs/10.txt
Normal file
3
fastlane/metadata/android/en-US/changelogs/10.txt
Normal 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.
|
5
fastlane/metadata/android/en-US/changelogs/11.txt
Normal file
5
fastlane/metadata/android/en-US/changelogs/11.txt
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
The same as release 1.3.3, but not the one bug is actually fixed for real...
|
||||||
|
* 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.
|
||||||
|
|
6
fastlane/metadata/android/en-US/changelogs/12.txt
Normal file
6
fastlane/metadata/android/en-US/changelogs/12.txt
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
* It is finally possible to add book covers from your own device storage.
|
||||||
|
* You can now return to the initial log-in screen by long-pressing the 'back' button.
|
||||||
|
* Dependencies have been updated to newest versions.
|
||||||
|
* Compiled for up to Android 14 now.
|
||||||
|
* Deprecated pieces of code have been rewritten.
|
||||||
|
* More Bookwyrm instances have been added.
|
3
fastlane/metadata/android/en-US/changelogs/6.txt
Normal file
3
fastlane/metadata/android/en-US/changelogs/6.txt
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
Initial release for F-Droid.
|
||||||
|
|
||||||
|
* Added support for four more BookWyrm instances.
|
5
fastlane/metadata/android/en-US/changelogs/7.txt
Normal file
5
fastlane/metadata/android/en-US/changelogs/7.txt
Normal 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...
|
6
fastlane/metadata/android/en-US/changelogs/8.txt
Normal file
6
fastlane/metadata/android/en-US/changelogs/8.txt
Normal 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.
|
2
fastlane/metadata/android/en-US/changelogs/9.txt
Normal file
2
fastlane/metadata/android/en-US/changelogs/9.txt
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
* Changed the initial screen to dark mode.
|
||||||
|
* The login screen things are now better aligned.
|
10
fastlane/metadata/android/en-US/full_description.txt
Normal file
10
fastlane/metadata/android/en-US/full_description.txt
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
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:
|
||||||
|
|
||||||
|
* 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.
|
BIN
fastlane/metadata/android/en-US/images/icon.png
Normal file
BIN
fastlane/metadata/android/en-US/images/icon.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 25 KiB |
BIN
fastlane/metadata/android/en-US/images/phoneScreenshots/1.png
Normal file
BIN
fastlane/metadata/android/en-US/images/phoneScreenshots/1.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 318 KiB |
BIN
fastlane/metadata/android/en-US/images/phoneScreenshots/2.png
Normal file
BIN
fastlane/metadata/android/en-US/images/phoneScreenshots/2.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 247 KiB |
BIN
fastlane/metadata/android/en-US/images/phoneScreenshots/3.png
Normal file
BIN
fastlane/metadata/android/en-US/images/phoneScreenshots/3.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 203 KiB |
BIN
fastlane/metadata/android/en-US/images/phoneScreenshots/4.png
Normal file
BIN
fastlane/metadata/android/en-US/images/phoneScreenshots/4.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 45 KiB |
BIN
fastlane/metadata/android/en-US/images/phoneScreenshots/5.png
Normal file
BIN
fastlane/metadata/android/en-US/images/phoneScreenshots/5.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.1 MiB |
1
fastlane/metadata/android/en-US/short_description.txt
Normal file
1
fastlane/metadata/android/en-US/short_description.txt
Normal file
@ -0,0 +1 @@
|
|||||||
|
A BookWyrm client for Android.
|
1
fastlane/metadata/android/en-US/title.txt
Normal file
1
fastlane/metadata/android/en-US/title.txt
Normal file
@ -0,0 +1 @@
|
|||||||
|
BookWyrm
|
@ -15,3 +15,8 @@ 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
|
||||||
|
android.defaults.buildfeatures.buildconfig=true
|
||||||
|
android.nonFinalResIds=false
|
2
gradle/wrapper/gradle-wrapper.properties
vendored
2
gradle/wrapper/gradle-wrapper.properties
vendored
@ -1,6 +1,6 @@
|
|||||||
#Mon Feb 14 18:09:26 CET 2022
|
#Mon Feb 14 18:09:26 CET 2022
|
||||||
distributionBase=GRADLE_USER_HOME
|
distributionBase=GRADLE_USER_HOME
|
||||||
distributionUrl=https\://services.gradle.org/distributions/gradle-7.2-bin.zip
|
distributionUrl=https\://services.gradle.org/distributions/gradle-8.9-bin.zip
|
||||||
distributionPath=wrapper/dists
|
distributionPath=wrapper/dists
|
||||||
zipStorePath=wrapper/dists
|
zipStorePath=wrapper/dists
|
||||||
zipStoreBase=GRADLE_USER_HOME
|
zipStoreBase=GRADLE_USER_HOME
|
||||||
|
@ -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'
|
Reference in New Issue
Block a user