Compare commits
239 Commits
v1.0.0
...
android_ap
Author | SHA1 | Date | |
---|---|---|---|
a12584d636
|
|||
86ad6986b1
|
|||
c0b5119a8e
|
|||
9f3e183d72
|
|||
51f5f1005a
|
|||
0a380f861e
|
|||
b712ad3488
|
|||
9f656bdefe
|
|||
a4a651229c
|
|||
4773800f23
|
|||
bef0b8189e
|
|||
674714f0f3
|
|||
ee9e858584
|
|||
165c6d8614
|
|||
8a6719fc19
|
|||
308361a834
|
|||
44df964f6f
|
|||
56bf266919
|
|||
f3658d6636
|
|||
1bb37eec30
|
|||
59511b2345
|
|||
5b7bc02c61
|
|||
b329f537e7
|
|||
5879e81759
|
|||
f4e88bef77
|
|||
b3ec45309c
|
|||
2fbc892898
|
|||
c46190c3fc
|
|||
860e540de1
|
|||
8cde286cac
|
|||
90830fe384
|
|||
686f89f75d
|
|||
4210af5680
|
|||
aefc368cfd
|
|||
67218d8045
|
|||
c05deb3a41
|
|||
43d0107fb5
|
|||
ece7612f9d
|
|||
a9809d90cb
|
|||
bbc9a79996
|
|||
b71f1885ec
|
|||
885aad2047
|
|||
7121afab08
|
|||
d9a4c4ffd6
|
|||
fb826919a6
|
|||
22720169a2
|
|||
7fefd251db
|
|||
5de4f67344
|
|||
d396a12d68
|
|||
3888c91a6b
|
|||
562bac6987
|
|||
e825b4dd85
|
|||
08587b7a7a
|
|||
0daca2cf8f
|
|||
3a9b15c2be
|
|||
e9b4db0f1c
|
|||
312a31ce9e
|
|||
d4a8a2e720
|
|||
dcb4f253d8
|
|||
d0a04bae84
|
|||
34ac96edd7
|
|||
b42ce84c3e
|
|||
2db779b44f
|
|||
397bfe78aa
|
|||
efaad3f97c
|
|||
624c613bd1
|
|||
07b0632c95
|
|||
3d1e6cfa17
|
|||
3db636d41a
|
|||
2053b8f07f
|
|||
b1681b53e4
|
|||
03f60ff316
|
|||
b2df0a5a02
|
|||
8826cb0312
|
|||
a0c72f5b94
|
|||
7d9a58ae54
|
|||
fd72b512f8
|
|||
28c2721036
|
|||
a1788bf75a
|
|||
b1bd278f9b
|
|||
16f6ab4861
|
|||
01934e29b1
|
|||
d1cefb0150
|
|||
27b189d33a
|
|||
e05d88682a
|
|||
2a5f1f5f7e
|
|||
e7a45d9a05
|
|||
ec9a326002
|
|||
23c7729fcf
|
|||
7fcd324299
|
|||
1633449638
|
|||
57231a1406
|
|||
2eb6292733
|
|||
ff24493ff3
|
|||
3d602af135
|
|||
590665a5e9
|
|||
89fd0dfed7
|
|||
82bc887767
|
|||
acd7de0dee
|
|||
e737cd9d5c
|
|||
0ec7a9d274
|
|||
e49d9159e4
|
|||
3343285761
|
|||
14bba38324
|
|||
679277d59e
|
|||
cebb2ae2b6
|
|||
56d9f977ae
|
|||
984470b47d
|
|||
0112d681ac
|
|||
0cb2a977a0
|
|||
f65c231ba0
|
|||
dbc014f819
|
|||
bbf7962e29
|
|||
2b4d77bab4
|
|||
8582674b44
|
|||
f7675be834
|
|||
00d77e508d
|
|||
e90cfe34e9
|
|||
54dfd535a4
|
|||
5a02eb6d18
|
|||
97fc9319d1
|
|||
03b4acd13e
|
|||
86f06a3c6a
|
|||
06e8d2a6e2
|
|||
99f248a8ce
|
|||
c7aaa6ad98
|
|||
cb5ce66c1a
|
|||
0750bf1d8a
|
|||
203360e8b5
|
|||
ef1844109f
|
|||
de6ad35f60
|
|||
fbb289dedf
|
|||
f1e87170f0
|
|||
66ecad27a7
|
|||
98b1e8bd80
|
|||
26cd1533b4
|
|||
3692b915f3
|
|||
06788c3e12
|
|||
edfcdd1135
|
|||
dd2f3baa0c
|
|||
7db70e392b
|
|||
0cae24a612
|
|||
8db0fa37db
|
|||
d27e3d9a91
|
|||
fa5a4107a6
|
|||
234188c4d4
|
|||
9b700581f3
|
|||
12db23d076
|
|||
fd182f0abb
|
|||
7eab74e65c
|
|||
e0ecd4d9ff
|
|||
1ca09c16d3
|
|||
a7df476e79
|
|||
4e5eac6178
|
|||
91a6808ad2
|
|||
11a6517156
|
|||
7aa7eb234d
|
|||
62d7df9710
|
|||
0ff1188c3d
|
|||
b6e8d037a0
|
|||
7a11b2c76f
|
|||
7f56dbdbfa
|
|||
df4eb15df8
|
|||
ac9ae06cc8
|
|||
464cf3ec7e
|
|||
bf0ce5c963
|
|||
3a0c65a849
|
|||
6d80638cf8
|
|||
37e09d6532
|
|||
8ea3fdcfef
|
|||
1bc847cdc9
|
|||
03c35d6446
|
|||
d5aea1a828
|
|||
f17ddb4ace
|
|||
0cc6e27267
|
|||
ca58aa782d
|
|||
e8671e8650
|
|||
d46601be5c
|
|||
d30e2cefc0
|
|||
08a93551e7
|
|||
c2899fd727
|
|||
5ec66e1777
|
|||
516809cd02
|
|||
0d3526221d
|
|||
728b12107f
|
|||
b56c021356
|
|||
80f3b982d2
|
|||
0d641b727f
|
|||
8278c059ad
|
|||
7af0ff5413
|
|||
5c2877bdb8
|
|||
85bfe79115
|
|||
fb37f94c0a
|
|||
e53f40866e
|
|||
650ba20e5d
|
|||
6e01c41c22
|
|||
f555f0f1cf
|
|||
35ef2175bc
|
|||
55f53deadf
|
|||
5991631bfa
|
|||
34a27d9ca4
|
|||
1671490485
|
|||
0e58a5c5f0
|
|||
![]() |
bd11d7973c | ||
f3b5b09ed0
|
|||
ce641bf7d2
|
|||
f1c7314dca
|
|||
019408dc6d
|
|||
![]() |
cdba3540c2 | ||
885d997ff3
|
|||
5118ab3cbf
|
|||
![]() |
2812377f5c | ||
93b40a9c7f
|
|||
b95ddcc811
|
|||
90ba3c1134
|
|||
05174958b2
|
|||
![]() |
24be9b2013 | ||
29ce4b727c
|
|||
![]() |
f178019ffe | ||
0a1b948042
|
|||
![]() |
74cbfb235e | ||
63c4104a89
|
|||
2597287b1e
|
|||
![]() |
316156f0f0 | ||
5286e869cc
|
|||
d6dcf28d89
|
|||
1d983b9ac0
|
|||
e525221010
|
|||
4cde4703f2
|
|||
4a07e58c16
|
|||
b12356575a
|
|||
77f571de7d
|
|||
![]() |
f5eef7563b | ||
741c09b1e4
|
|||
0c0d7d181f
|
|||
9304da9422
|
|||
![]() |
d7afdd00f2 | ||
b780ccea1c
|
|||
![]() |
5d8e871871 |
43
.gitea/workflows/build_and_deploy.yml
Normal file
43
.gitea/workflows/build_and_deploy.yml
Normal file
@@ -0,0 +1,43 @@
|
||||
|
||||
# https://docs.gitea.com/next/usage/actions/quickstart
|
||||
# https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions
|
||||
# https://docs.github.com/en/actions/learn-github-actions/contexts#github-context
|
||||
|
||||
name: Build Docker and Deploy
|
||||
run-name: Build & Deploy ${{ gitea.ref }} on ${{ gitea.actor }}
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: ['master']
|
||||
|
||||
|
||||
|
||||
jobs:
|
||||
build_job:
|
||||
name: Build Docker Container
|
||||
runs-on: bfb-cicd-latest
|
||||
steps:
|
||||
- run: echo -n "${{ secrets.DOCKER_REG_PASS }}" | docker login registry.blackforestbytes.com -u docker --password-stdin
|
||||
- name: Check out code
|
||||
uses: actions/checkout@v3
|
||||
- run: cd "${{ gitea.workspace }}/scnserver" && make clean
|
||||
- run: cd "${{ gitea.workspace }}/scnserver" && make docker
|
||||
- run: cd "${{ gitea.workspace }}/scnserver" && make push-docker
|
||||
|
||||
deploy_job:
|
||||
name: Deploy to Server
|
||||
needs: [build_job]
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Execute deploy on remote (via ssh)
|
||||
uses: appleboy/ssh-action@v1.0.0
|
||||
with:
|
||||
host: simplecloudnotifier.de
|
||||
username: bfb-deploy-bot
|
||||
port: 4477
|
||||
key: "${{ secrets.SSH_KEY_BFBDEPLOYBOT }}"
|
||||
script: cd /var/docker/deploy-scripts/simplecloudnotifier && ./deploy.sh master "${{ gitea.sha }}" || exit 1
|
||||
|
||||
|
||||
|
||||
|
85
android/.idea/assetWizardSettings.xml
generated
85
android/.idea/assetWizardSettings.xml
generated
@@ -1,85 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="WizardSettings">
|
||||
<option name="children">
|
||||
<map>
|
||||
<entry key="imageWizard">
|
||||
<value>
|
||||
<PersistentState>
|
||||
<option name="children">
|
||||
<map>
|
||||
<entry key="imageAssetPanel">
|
||||
<value>
|
||||
<PersistentState>
|
||||
<option name="children">
|
||||
<map>
|
||||
<entry key="launcherLegacy">
|
||||
<value>
|
||||
<PersistentState>
|
||||
<option name="values">
|
||||
<map>
|
||||
<entry key="assetType" value="IMAGE" />
|
||||
<entry key="cropped" value="true" />
|
||||
<entry key="iconShape" value="NONE" />
|
||||
<entry key="imageAsset" value="F:\Eigene Dateien\Dropbox\Programming\Java\AndroidStudioProjects\SimpleCloudNotifier\data\icon_512_nobox.png" />
|
||||
<entry key="outputName" value="ic_notification_full" />
|
||||
</map>
|
||||
</option>
|
||||
</PersistentState>
|
||||
</value>
|
||||
</entry>
|
||||
<entry key="notification">
|
||||
<value>
|
||||
<PersistentState>
|
||||
<option name="values">
|
||||
<map>
|
||||
<entry key="assetType" value="IMAGE" />
|
||||
<entry key="imageAsset" value="F:\Eigene Dateien\Dropbox\Programming\Java\AndroidStudioProjects\SimpleCloudNotifier\data\icon_512_transparent.png" />
|
||||
<entry key="outputName" value="ic_notification_white" />
|
||||
</map>
|
||||
</option>
|
||||
</PersistentState>
|
||||
</value>
|
||||
</entry>
|
||||
</map>
|
||||
</option>
|
||||
<option name="values">
|
||||
<map>
|
||||
<entry key="outputIconType" value="LAUNCHER_LEGACY" />
|
||||
</map>
|
||||
</option>
|
||||
</PersistentState>
|
||||
</value>
|
||||
</entry>
|
||||
</map>
|
||||
</option>
|
||||
</PersistentState>
|
||||
</value>
|
||||
</entry>
|
||||
<entry key="vectorWizard">
|
||||
<value>
|
||||
<PersistentState>
|
||||
<option name="children">
|
||||
<map>
|
||||
<entry key="vectorAssetStep">
|
||||
<value>
|
||||
<PersistentState>
|
||||
<option name="values">
|
||||
<map>
|
||||
<entry key="assetSourceType" value="FILE" />
|
||||
<entry key="outputName" value="ic_garbage" />
|
||||
<entry key="sourceFile" value="C:\Users\Mike\Downloads\garbage.svg" />
|
||||
</map>
|
||||
</option>
|
||||
</PersistentState>
|
||||
</value>
|
||||
</entry>
|
||||
</map>
|
||||
</option>
|
||||
</PersistentState>
|
||||
</value>
|
||||
</entry>
|
||||
</map>
|
||||
</option>
|
||||
</component>
|
||||
</project>
|
134
android/.idea/codeStyles/Project.xml
generated
134
android/.idea/codeStyles/Project.xml
generated
@@ -1,29 +1,113 @@
|
||||
<component name="ProjectCodeStyleConfiguration">
|
||||
<code_scheme name="Project" version="173">
|
||||
<Objective-C-extensions>
|
||||
<file>
|
||||
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Import" />
|
||||
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Macro" />
|
||||
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Typedef" />
|
||||
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Enum" />
|
||||
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Constant" />
|
||||
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Global" />
|
||||
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Struct" />
|
||||
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="FunctionPredecl" />
|
||||
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Function" />
|
||||
</file>
|
||||
<class>
|
||||
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Property" />
|
||||
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Synthesize" />
|
||||
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="InitMethod" />
|
||||
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="StaticMethod" />
|
||||
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="InstanceMethod" />
|
||||
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="DeallocMethod" />
|
||||
</class>
|
||||
<extensions>
|
||||
<pair source="cpp" header="h" fileNamingConvention="NONE" />
|
||||
<pair source="c" header="h" fileNamingConvention="NONE" />
|
||||
</extensions>
|
||||
</Objective-C-extensions>
|
||||
<codeStyleSettings language="XML">
|
||||
<arrangement>
|
||||
<rules>
|
||||
<section>
|
||||
<rule>
|
||||
<match>
|
||||
<AND>
|
||||
<NAME>xmlns:android</NAME>
|
||||
<XML_ATTRIBUTE />
|
||||
<XML_NAMESPACE>^$</XML_NAMESPACE>
|
||||
</AND>
|
||||
</match>
|
||||
</rule>
|
||||
</section>
|
||||
<section>
|
||||
<rule>
|
||||
<match>
|
||||
<AND>
|
||||
<NAME>xmlns:.*</NAME>
|
||||
<XML_ATTRIBUTE />
|
||||
<XML_NAMESPACE>^$</XML_NAMESPACE>
|
||||
</AND>
|
||||
</match>
|
||||
<order>BY_NAME</order>
|
||||
</rule>
|
||||
</section>
|
||||
<section>
|
||||
<rule>
|
||||
<match>
|
||||
<AND>
|
||||
<NAME>.*:id</NAME>
|
||||
<XML_ATTRIBUTE />
|
||||
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
|
||||
</AND>
|
||||
</match>
|
||||
</rule>
|
||||
</section>
|
||||
<section>
|
||||
<rule>
|
||||
<match>
|
||||
<AND>
|
||||
<NAME>.*:name</NAME>
|
||||
<XML_ATTRIBUTE />
|
||||
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
|
||||
</AND>
|
||||
</match>
|
||||
</rule>
|
||||
</section>
|
||||
<section>
|
||||
<rule>
|
||||
<match>
|
||||
<AND>
|
||||
<NAME>name</NAME>
|
||||
<XML_ATTRIBUTE />
|
||||
<XML_NAMESPACE>^$</XML_NAMESPACE>
|
||||
</AND>
|
||||
</match>
|
||||
</rule>
|
||||
</section>
|
||||
<section>
|
||||
<rule>
|
||||
<match>
|
||||
<AND>
|
||||
<NAME>style</NAME>
|
||||
<XML_ATTRIBUTE />
|
||||
<XML_NAMESPACE>^$</XML_NAMESPACE>
|
||||
</AND>
|
||||
</match>
|
||||
</rule>
|
||||
</section>
|
||||
<section>
|
||||
<rule>
|
||||
<match>
|
||||
<AND>
|
||||
<NAME>.*</NAME>
|
||||
<XML_ATTRIBUTE />
|
||||
<XML_NAMESPACE>^$</XML_NAMESPACE>
|
||||
</AND>
|
||||
</match>
|
||||
<order>BY_NAME</order>
|
||||
</rule>
|
||||
</section>
|
||||
<section>
|
||||
<rule>
|
||||
<match>
|
||||
<AND>
|
||||
<NAME>.*</NAME>
|
||||
<XML_ATTRIBUTE />
|
||||
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
|
||||
</AND>
|
||||
</match>
|
||||
<order>ANDROID_ATTRIBUTE_ORDER</order>
|
||||
</rule>
|
||||
</section>
|
||||
<section>
|
||||
<rule>
|
||||
<match>
|
||||
<AND>
|
||||
<NAME>.*</NAME>
|
||||
<XML_ATTRIBUTE />
|
||||
<XML_NAMESPACE>.*</XML_NAMESPACE>
|
||||
</AND>
|
||||
</match>
|
||||
<order>BY_NAME</order>
|
||||
</rule>
|
||||
</section>
|
||||
</rules>
|
||||
</arrangement>
|
||||
</codeStyleSettings>
|
||||
</code_scheme>
|
||||
</component>
|
40
android/.idea/jarRepositories.xml
generated
Normal file
40
android/.idea/jarRepositories.xml
generated
Normal file
@@ -0,0 +1,40 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="RemoteRepositoriesConfiguration">
|
||||
<remote-repository>
|
||||
<option name="id" value="central" />
|
||||
<option name="name" value="Maven Central repository" />
|
||||
<option name="url" value="https://repo1.maven.org/maven2" />
|
||||
</remote-repository>
|
||||
<remote-repository>
|
||||
<option name="id" value="jboss.community" />
|
||||
<option name="name" value="JBoss Community repository" />
|
||||
<option name="url" value="https://repository.jboss.org/nexus/content/repositories/public/" />
|
||||
</remote-repository>
|
||||
<remote-repository>
|
||||
<option name="id" value="maven2" />
|
||||
<option name="name" value="maven2" />
|
||||
<option name="url" value="https://dl.bintray.com/gericop/maven" />
|
||||
</remote-repository>
|
||||
<remote-repository>
|
||||
<option name="id" value="maven3" />
|
||||
<option name="name" value="maven3" />
|
||||
<option name="url" value="https://maven.google.com" />
|
||||
</remote-repository>
|
||||
<remote-repository>
|
||||
<option name="id" value="BintrayJCenter" />
|
||||
<option name="name" value="BintrayJCenter" />
|
||||
<option name="url" value="https://jcenter.bintray.com/" />
|
||||
</remote-repository>
|
||||
<remote-repository>
|
||||
<option name="id" value="maven" />
|
||||
<option name="name" value="maven" />
|
||||
<option name="url" value="https://jitpack.io" />
|
||||
</remote-repository>
|
||||
<remote-repository>
|
||||
<option name="id" value="Google" />
|
||||
<option name="name" value="Google" />
|
||||
<option name="url" value="https://dl.google.com/dl/android/maven2/" />
|
||||
</remote-repository>
|
||||
</component>
|
||||
</project>
|
@@ -1,7 +1,7 @@
|
||||
apply plugin: 'com.android.application'
|
||||
|
||||
android {
|
||||
compileSdkVersion 28
|
||||
compileSdkVersion 30
|
||||
|
||||
def versionPropsFile = file('version.properties')
|
||||
def vNumber
|
||||
@@ -16,7 +16,7 @@ android {
|
||||
defaultConfig {
|
||||
applicationId "com.blackforestbytes.simplecloudnotifier"
|
||||
minSdkVersion 21
|
||||
targetSdkVersion 28
|
||||
targetSdkVersion 30
|
||||
versionCode vNumber
|
||||
versionName vName
|
||||
}
|
||||
@@ -35,28 +35,33 @@ android {
|
||||
dependencies {
|
||||
implementation fileTree(dir: 'libs', include: ['*.jar'])
|
||||
|
||||
implementation 'androidx.appcompat:appcompat:1.0.2'
|
||||
implementation 'androidx.appcompat:appcompat:1.2.0'
|
||||
implementation 'androidx.cardview:cardview:1.0.0'
|
||||
implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
|
||||
implementation 'androidx.recyclerview:recyclerview:1.0.0'
|
||||
implementation 'androidx.recyclerview:recyclerview:1.0.0'
|
||||
implementation 'androidx.lifecycle:lifecycle-extensions:2.0.0'
|
||||
implementation 'androidx.constraintlayout:constraintlayout:2.0.4'
|
||||
implementation 'androidx.recyclerview:recyclerview:1.1.0'
|
||||
implementation 'androidx.recyclerview:recyclerview:1.1.0'
|
||||
implementation 'androidx.lifecycle:lifecycle-extensions:2.2.0'
|
||||
|
||||
implementation 'com.google.android.material:material:1.0.0'
|
||||
implementation 'com.google.firebase:firebase-core:16.0.4'
|
||||
implementation 'com.google.firebase:firebase-messaging:17.3.4'
|
||||
implementation 'com.google.android.gms:play-services-ads:17.1.0'
|
||||
implementation 'com.android.billingclient:billing:1.2'
|
||||
implementation 'com.google.android.material:material:1.2.1'
|
||||
implementation 'com.google.firebase:firebase-core:18.0.0'
|
||||
implementation 'com.google.firebase:firebase-messaging:21.0.0'
|
||||
implementation 'com.google.android.gms:play-services-ads:19.5.0'
|
||||
implementation 'com.android.billingclient:billing:3.0.1'
|
||||
|
||||
implementation 'com.squareup.okhttp3:okhttp:3.10.0'
|
||||
implementation 'com.squareup.okhttp3:okhttp:4.9.0'
|
||||
implementation 'com.github.kenglxn.QRGen:android:2.5.0'
|
||||
implementation "com.github.DeweyReed:UltimateMusicPicker:2.0.0"
|
||||
implementation 'com.github.duanhong169:colorpicker:1.1.5'
|
||||
|
||||
implementation 'net.danlew:android.joda:2.10.7.1'
|
||||
}
|
||||
|
||||
apply plugin: 'com.google.gms.google-services'
|
||||
|
||||
task updateVersion << {
|
||||
tasks.register("updateVersion") {
|
||||
group = 'Custom'
|
||||
|
||||
doLast {
|
||||
def lastTag = ['git', 'describe', "--abbrev=0", "--tags"].execute().text.trim()
|
||||
|
||||
def versionPropsFile = file('version.properties')
|
||||
@@ -108,3 +113,4 @@ task updateVersion << {
|
||||
versionPropsFile.newWriter().withCloseable { w -> versionProps.store(w, null) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -1,6 +1,5 @@
|
||||
<?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"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
package="com.blackforestbytes.simplecloudnotifier">
|
||||
|
||||
@@ -10,34 +9,60 @@
|
||||
<uses-permission android:name="com.android.vending.BILLING" />
|
||||
|
||||
<application
|
||||
android:name=".SCNApp"
|
||||
android:allowBackup="false"
|
||||
android:name="SCNApp"
|
||||
android:icon="@drawable/icon"
|
||||
android:label="@string/app_name"
|
||||
android:supportsRtl="true"
|
||||
android:theme="@style/AppTheme"
|
||||
tools:ignore="GoogleAppIndexingWarning">
|
||||
|
||||
<activity android:name=".view.MainActivity">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
|
||||
<meta-data android:name="com.google.firebase.messaging.default_notification_icon" android:resource="@drawable/icon" />
|
||||
<meta-data android:name="com.google.firebase.messaging.default_notification_color" android:resource="@color/colorAccent" />
|
||||
<meta-data android:name="com.google.android.gms.ads.AD_MANAGER_APP" android:value="true"/>
|
||||
<meta-data android:name="com.google.android.gms.ads.APPLICATION_ID" android:value="ca-app-pub-3320562328966175~7579972005"/>
|
||||
<provider
|
||||
android:name="androidx.core.content.FileProvider"
|
||||
android:authorities="com.blackforestbytes.simplecloudnotifier.fileprovider"
|
||||
android:grantUriPermissions="true"
|
||||
android:exported="false">
|
||||
<meta-data android:name="android.support.FILE_PROVIDER_PATHS" android:resource="@xml/filepaths" />
|
||||
</provider>
|
||||
|
||||
<service android:name=".service.FBMService" android:exported="false">
|
||||
|
||||
<meta-data
|
||||
android:name="com.google.firebase.messaging.default_notification_icon"
|
||||
android:resource="@drawable/icon" />
|
||||
<meta-data
|
||||
android:name="com.google.firebase.messaging.default_notification_color"
|
||||
android:resource="@color/colorAccent" />
|
||||
<meta-data
|
||||
android:name="com.google.android.gms.ads.AD_MANAGER_APP"
|
||||
android:value="true" />
|
||||
<meta-data
|
||||
android:name="com.google.android.gms.ads.APPLICATION_ID"
|
||||
android:value="ca-app-pub-3320562328966175~7579972005" />
|
||||
|
||||
<service
|
||||
android:name=".service.FBMService"
|
||||
android:exported="false">
|
||||
<intent-filter>
|
||||
<action android:name="com.google.firebase.MESSAGING_EVENT" />
|
||||
</intent-filter>
|
||||
</service>
|
||||
|
||||
<receiver android:name=".service.BroadcastReceiverService" android:exported="false" />
|
||||
<receiver
|
||||
android:name=".service.BroadcastReceiverService"
|
||||
android:exported="false" />
|
||||
|
||||
<activity
|
||||
android:name=".view.debug.QueryLogActivity"
|
||||
android:label="@string/title_activity_query_log"
|
||||
android:theme="@style/AppTheme" />
|
||||
<activity android:name=".view.debug.SingleQueryLogActivity" />
|
||||
</application>
|
||||
|
||||
</manifest>
|
@@ -5,6 +5,7 @@ import android.content.Context;
|
||||
import android.widget.Toast;
|
||||
|
||||
import com.android.billingclient.api.BillingClient;
|
||||
import com.blackforestbytes.simplecloudnotifier.model.QueryLog;
|
||||
import com.blackforestbytes.simplecloudnotifier.view.AccountFragment;
|
||||
import com.blackforestbytes.simplecloudnotifier.view.MainActivity;
|
||||
import com.blackforestbytes.simplecloudnotifier.view.TabAdapter;
|
||||
@@ -99,4 +100,5 @@ public class SCNApp extends Application implements LifecycleObserver
|
||||
}
|
||||
}
|
||||
|
||||
//TODO TabLayout indicator does not corretly animate when directly clicking on tabs
|
||||
//TODO: Config for collapsed line count
|
||||
//TODO: Sometimes ads but promode
|
||||
|
@@ -9,6 +9,8 @@ import java.util.TimeZone;
|
||||
|
||||
public class CMessage
|
||||
{
|
||||
public boolean IsExpandedInAdapter = false;
|
||||
|
||||
public final long SCN_ID;
|
||||
public final long Timestamp;
|
||||
public final String Title;
|
||||
|
@@ -35,6 +35,11 @@ public class CMessageList
|
||||
}
|
||||
|
||||
private CMessageList()
|
||||
{
|
||||
reloadPrefs();
|
||||
}
|
||||
|
||||
public void reloadPrefs()
|
||||
{
|
||||
synchronized (msg_lock)
|
||||
{
|
||||
|
@@ -0,0 +1,58 @@
|
||||
package com.blackforestbytes.simplecloudnotifier.model;
|
||||
|
||||
|
||||
import android.graphics.Color;
|
||||
|
||||
public enum LogLevel
|
||||
{
|
||||
DEBUG,
|
||||
INFO,
|
||||
WARN,
|
||||
ERROR;
|
||||
|
||||
public String toUIString()
|
||||
{
|
||||
switch (this)
|
||||
{
|
||||
case DEBUG: return "Debug";
|
||||
case INFO: return "Info";
|
||||
case WARN: return "Warning";
|
||||
case ERROR: return "Error";
|
||||
default: return "???";
|
||||
}
|
||||
}
|
||||
|
||||
public int getColor()
|
||||
{
|
||||
switch (this)
|
||||
{
|
||||
case DEBUG: return Color.GRAY;
|
||||
case WARN: return Color.rgb(171, 145, 68);
|
||||
case INFO: return Color.BLACK;
|
||||
case ERROR: return Color.RED;
|
||||
default: return Color.MAGENTA;
|
||||
}
|
||||
}
|
||||
|
||||
public int asInt()
|
||||
{
|
||||
switch (this)
|
||||
{
|
||||
case DEBUG: return 0;
|
||||
case WARN: return 1;
|
||||
case INFO: return 2;
|
||||
case ERROR: return 3;
|
||||
default: return 999;
|
||||
}
|
||||
}
|
||||
|
||||
public static LogLevel fromInt(int i)
|
||||
{
|
||||
if (i == 0) return LogLevel.DEBUG;
|
||||
if (i == 1) return LogLevel.WARN;
|
||||
if (i == 2) return LogLevel.INFO;
|
||||
if (i == 3) return LogLevel.ERROR;
|
||||
|
||||
return LogLevel.ERROR; // ????
|
||||
}
|
||||
}
|
@@ -0,0 +1,69 @@
|
||||
package com.blackforestbytes.simplecloudnotifier.model;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.SharedPreferences;
|
||||
import android.util.Log;
|
||||
|
||||
import com.blackforestbytes.simplecloudnotifier.SCNApp;
|
||||
import com.blackforestbytes.simplecloudnotifier.lib.collections.CollectionHelper;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class QueryLog
|
||||
{
|
||||
private final static int MAX_HISTORY_SIZE = 192;
|
||||
|
||||
private static QueryLog _instance;
|
||||
public static QueryLog inst() { if (_instance == null) synchronized (QueryLog.class) { if (_instance == null) _instance = new QueryLog(); } return _instance; }
|
||||
|
||||
private QueryLog(){ reloadPrefs(); }
|
||||
|
||||
private final List<SingleQuery> history = new ArrayList<>();
|
||||
|
||||
public synchronized void add(SingleQuery r)
|
||||
{
|
||||
history.add(r);
|
||||
while (history.size() > MAX_HISTORY_SIZE) history.remove(0);
|
||||
|
||||
save();
|
||||
}
|
||||
|
||||
public synchronized List<SingleQuery> get()
|
||||
{
|
||||
List<SingleQuery> r = new ArrayList<>(history);
|
||||
CollectionHelper.sort_inplace(r, (o1, o2) -> (-1) * o1.Timestamp.compareTo(o2.Timestamp));
|
||||
return r;
|
||||
}
|
||||
|
||||
public synchronized void save()
|
||||
{
|
||||
SharedPreferences sharedPref = SCNApp.getContext().getSharedPreferences("QueryLog", Context.MODE_PRIVATE);
|
||||
SharedPreferences.Editor e = sharedPref.edit();
|
||||
|
||||
e.clear();
|
||||
|
||||
e.putInt("history_count", history.size());
|
||||
|
||||
for (int i = 0; i < history.size(); i++) history.get(i).save(e, "message["+(i+1000)+"]");
|
||||
|
||||
e.apply();
|
||||
}
|
||||
|
||||
public synchronized void reloadPrefs()
|
||||
{
|
||||
try
|
||||
{
|
||||
Context c = SCNApp.getContext();
|
||||
SharedPreferences sharedPref = c.getSharedPreferences("QueryLog", Context.MODE_PRIVATE);
|
||||
int count = sharedPref.getInt("history_count", 0);
|
||||
for (int i=0; i < count; i++) history.add(SingleQuery.load(sharedPref, "message["+(i+1000)+"]"));
|
||||
|
||||
CollectionHelper.sort_inplace(history, (o1, o2) -> (-1) * o1.Timestamp.compareTo(o2.Timestamp));
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Log.e("SC:QL:Load", e.toString());
|
||||
}
|
||||
}
|
||||
}
|
@@ -6,11 +6,11 @@ import android.content.SharedPreferences;
|
||||
import android.util.Log;
|
||||
import android.view.View;
|
||||
|
||||
import com.android.billingclient.api.Purchase;
|
||||
import com.blackforestbytes.simplecloudnotifier.SCNApp;
|
||||
import com.blackforestbytes.simplecloudnotifier.lib.datatypes.Tuple3;
|
||||
import com.blackforestbytes.simplecloudnotifier.lib.string.Str;
|
||||
import com.blackforestbytes.simplecloudnotifier.service.IABService;
|
||||
import com.google.firebase.iid.FirebaseInstanceId;
|
||||
import com.google.firebase.installations.FirebaseInstallations;
|
||||
|
||||
public class SCNSettings
|
||||
{
|
||||
@@ -52,7 +52,8 @@ public class SCNSettings
|
||||
|
||||
public boolean Enabled = true;
|
||||
public int LocalCacheSize = 500;
|
||||
public boolean EnableDeleteSwipe = true;
|
||||
public boolean EnableDeleteSwipe = false;
|
||||
public int PreviewLineCount = 6;
|
||||
|
||||
public final NotificationSettings PriorityLow = new NotificationSettings(PriorityEnum.LOW);
|
||||
public final NotificationSettings PriorityNorm = new NotificationSettings(PriorityEnum.NORMAL);
|
||||
@@ -61,6 +62,11 @@ public class SCNSettings
|
||||
// ------------------------------------------------------------
|
||||
|
||||
public SCNSettings()
|
||||
{
|
||||
reloadPrefs();
|
||||
}
|
||||
|
||||
public void reloadPrefs()
|
||||
{
|
||||
SharedPreferences sharedPref = SCNApp.getContext().getSharedPreferences("Config", Context.MODE_PRIVATE);
|
||||
|
||||
@@ -77,6 +83,7 @@ public class SCNSettings
|
||||
Enabled = sharedPref.getBoolean("app_enabled", Enabled);
|
||||
LocalCacheSize = sharedPref.getInt("local_cache_size", LocalCacheSize);
|
||||
EnableDeleteSwipe = sharedPref.getBoolean("do_del_swipe", EnableDeleteSwipe);
|
||||
PreviewLineCount = sharedPref.getInt("preview_line_count", PreviewLineCount);
|
||||
|
||||
PriorityLow.EnableLED = sharedPref.getBoolean("priority_low:enabled_led", PriorityLow.EnableLED);
|
||||
PriorityLow.EnableSound = sharedPref.getBoolean("priority_low:enabled_sound", PriorityLow.EnableSound);
|
||||
@@ -120,10 +127,14 @@ public class SCNSettings
|
||||
e.putString( "user_key", user_key);
|
||||
e.putString( "fcm_token_local", fcm_token_local);
|
||||
e.putString( "fcm_token_server", fcm_token_server);
|
||||
e.putBoolean("promode_local", promode_local);
|
||||
e.putBoolean("promode_server", promode_server);
|
||||
e.putString( "promode_token", promode_token);
|
||||
|
||||
e.putBoolean("app_enabled", Enabled);
|
||||
e.putInt( "local_cache_size", LocalCacheSize);
|
||||
e.putBoolean("do_del_swipe", EnableDeleteSwipe);
|
||||
e.putInt( "preview_line_count", PreviewLineCount);
|
||||
|
||||
e.putBoolean("priority_low:enabled_led", PriorityLow.EnableLED);
|
||||
e.putBoolean("priority_low:enabled_sound", PriorityLow.EnableSound);
|
||||
@@ -171,13 +182,13 @@ public class SCNSettings
|
||||
return base + "index.php?preset_user_id="+user_id+"&preset_user_key="+user_key;
|
||||
}
|
||||
|
||||
public void setServerToken(String token, View loader)
|
||||
public void setServerToken(String token, View loader, boolean force)
|
||||
{
|
||||
if (isConnected())
|
||||
{
|
||||
fcm_token_local = token;
|
||||
save();
|
||||
if (!fcm_token_local.equals(fcm_token_server)) ServerCommunication.updateFCMToken(user_id, user_key, fcm_token_local, loader);
|
||||
if (!fcm_token_local.equals(fcm_token_server) || force) ServerCommunication.updateFCMToken(user_id, user_key, fcm_token_local, loader);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -189,13 +200,12 @@ public class SCNSettings
|
||||
}
|
||||
|
||||
// called at app start
|
||||
public void work(Activity a)
|
||||
public void work(Activity a, boolean force)
|
||||
{
|
||||
FirebaseInstanceId.getInstance().getInstanceId().addOnSuccessListener(a, instanceIdResult ->
|
||||
FirebaseInstallations.getInstance().getId().addOnSuccessListener(a, newToken ->
|
||||
{
|
||||
String newToken = instanceIdResult.getToken();
|
||||
Log.d("FB::GetInstanceId", newToken);
|
||||
SCNSettings.inst().setServerToken(newToken, null);
|
||||
SCNSettings.inst().setServerToken(newToken, null, force);
|
||||
}).addOnCompleteListener(r ->
|
||||
{
|
||||
if (isConnected()) ServerCommunication.info(user_id, user_key, null);
|
||||
@@ -221,16 +231,15 @@ public class SCNSettings
|
||||
|
||||
if (promode_server != promode_local) updateProState(loader);
|
||||
|
||||
if (!Str.equals(fcm_token_local, fcm_token_server)) work(a);
|
||||
if (!Str.equals(fcm_token_local, fcm_token_server)) work(a, false);
|
||||
}
|
||||
else
|
||||
{
|
||||
// get token then register
|
||||
FirebaseInstanceId.getInstance().getInstanceId().addOnSuccessListener(a, instanceIdResult ->
|
||||
FirebaseInstallations.getInstance().getId().addOnSuccessListener(a, newToken ->
|
||||
{
|
||||
String newToken = instanceIdResult.getToken();
|
||||
Log.d("FB::GetInstanceId", newToken);
|
||||
SCNSettings.inst().setServerToken(newToken, loader); // does register in here
|
||||
SCNSettings.inst().setServerToken(newToken, loader, false); // does register in here
|
||||
}).addOnCompleteListener(r ->
|
||||
{
|
||||
if (isConnected()) ServerCommunication.info(user_id, user_key, null); // info again for safety
|
||||
@@ -240,14 +249,17 @@ public class SCNSettings
|
||||
|
||||
public void updateProState(View loader)
|
||||
{
|
||||
Purchase purch = IABService.inst().getPurchaseCached(IABService.IAB_PRO_MODE);
|
||||
boolean promode_real = (purch != null);
|
||||
Tuple3<Boolean, Boolean, String> state = IABService.inst().getPurchaseCachedExtended(IABService.IAB_PRO_MODE);
|
||||
if (!state.Item2) return; // not initialized
|
||||
|
||||
boolean promode_real = state.Item1;
|
||||
|
||||
if (promode_real != promode_local || promode_real != promode_server)
|
||||
{
|
||||
promode_local = promode_real;
|
||||
promode_token = promode_real ? state.Item3 : "";
|
||||
save();
|
||||
|
||||
promode_token = promode_real ? purch.getPurchaseToken() : "";
|
||||
updateProStateOnServer(loader);
|
||||
}
|
||||
}
|
||||
|
@@ -4,12 +4,11 @@ import android.util.Log;
|
||||
import android.view.View;
|
||||
|
||||
import com.blackforestbytes.simplecloudnotifier.SCNApp;
|
||||
import com.blackforestbytes.simplecloudnotifier.lib.datatypes.Tuple5;
|
||||
import com.blackforestbytes.simplecloudnotifier.lib.lambda.Func1to0;
|
||||
import com.blackforestbytes.simplecloudnotifier.lib.lambda.Func5to0;
|
||||
import com.blackforestbytes.simplecloudnotifier.lib.string.Str;
|
||||
import com.blackforestbytes.simplecloudnotifier.service.FBMService;
|
||||
|
||||
import org.joda.time.Instant;
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
@@ -48,20 +47,20 @@ public class ServerCommunication
|
||||
@Override
|
||||
public void onFailure(Call call, IOException e)
|
||||
{
|
||||
Log.e("SC:register", e.toString());
|
||||
SCNApp.showToast("Communication with server failed", 4000);
|
||||
handleError("register", call, null, Str.Empty, true, e);
|
||||
SCNApp.runOnUiThread(() -> { if (loader!=null)loader.setVisibility(View.GONE); });
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResponse(Call call, Response response)
|
||||
{
|
||||
String r = Str.Empty;
|
||||
try (ResponseBody responseBody = response.body())
|
||||
{
|
||||
if (!response.isSuccessful()) throw new IOException("Unexpected code " + response);
|
||||
if (responseBody == null) throw new IOException("No response");
|
||||
|
||||
String r = responseBody.string();
|
||||
r = responseBody.string();
|
||||
Log.d("Server::Response", request.url().toString()+"\n"+r);
|
||||
|
||||
JSONObject json = (JSONObject) new JSONTokener(r).nextValue();
|
||||
@@ -69,6 +68,7 @@ public class ServerCommunication
|
||||
if (!json_bool(json, "success"))
|
||||
{
|
||||
SCNApp.showToast(json_str(json, "message"), 4000);
|
||||
handleNonSuccess("register", call, response, r);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -81,11 +81,12 @@ public class ServerCommunication
|
||||
SCNSettings.inst().save();
|
||||
|
||||
SCNApp.refreshAccountTab();
|
||||
|
||||
handleSuccess("register", call, response, r);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Log.e("SC:register", e.toString());
|
||||
SCNApp.showToast("Communication with server failed", 4000);
|
||||
handleError("register", call, response, r, false, e);
|
||||
}
|
||||
finally
|
||||
{
|
||||
@@ -96,8 +97,7 @@ public class ServerCommunication
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Log.e("SC:register", e.toString());
|
||||
SCNApp.showToast("Communication with server failed", 4000);
|
||||
handleError("register", null, null, Str.Empty, false, e);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -106,7 +106,7 @@ public class ServerCommunication
|
||||
try
|
||||
{
|
||||
Request request = new Request.Builder()
|
||||
.url(BASE_URL + "updateFCMToken.php?user_id="+id+"&user_key="+key+"&fcm_token="+token)
|
||||
.url(BASE_URL + "update.php?user_id="+id+"&user_key="+key+"&fcm_token="+token)
|
||||
.build();
|
||||
|
||||
client.newCall(request).enqueue(new Callback()
|
||||
@@ -114,20 +114,20 @@ public class ServerCommunication
|
||||
@Override
|
||||
public void onFailure(Call call, IOException e)
|
||||
{
|
||||
Log.e("SC:update_1", e.toString());
|
||||
SCNApp.showToast("Communication with server failed", 4000);
|
||||
handleError("update<1>", call, null, Str.Empty, true, e);
|
||||
SCNApp.runOnUiThread(() -> { if (loader!=null)loader.setVisibility(View.GONE); });
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResponse(Call call, Response response)
|
||||
{
|
||||
String r = Str.Empty;
|
||||
try (ResponseBody responseBody = response.body())
|
||||
{
|
||||
if (!response.isSuccessful()) throw new IOException("Unexpected code " + response);
|
||||
if (responseBody == null) throw new IOException("No response");
|
||||
|
||||
String r = responseBody.string();
|
||||
r = responseBody.string();
|
||||
Log.d("Server::Response", request.url().toString()+"\n"+r);
|
||||
|
||||
JSONObject json = (JSONObject) new JSONTokener(r).nextValue();
|
||||
@@ -135,6 +135,7 @@ public class ServerCommunication
|
||||
if (!json_bool(json, "success"))
|
||||
{
|
||||
SCNApp.showToast(json_str(json, "message"), 4000);
|
||||
handleNonSuccess("update<1>", call, response, r);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -147,10 +148,12 @@ public class ServerCommunication
|
||||
SCNSettings.inst().save();
|
||||
|
||||
SCNApp.refreshAccountTab();
|
||||
|
||||
handleSuccess("update<1>", call, response, r);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Log.e("SC:update_1", e.toString());
|
||||
handleError("update<1>", call, response, r, false, e);
|
||||
SCNApp.showToast("Communication with server failed", 4000);
|
||||
}
|
||||
finally
|
||||
@@ -162,8 +165,7 @@ public class ServerCommunication
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Log.e("SC:update_1", e.toString());
|
||||
SCNApp.showToast("Communication with server failed", 4000);
|
||||
handleError("update<1>", null, null, Str.Empty, false, e);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -172,30 +174,35 @@ public class ServerCommunication
|
||||
try
|
||||
{
|
||||
Request request = new Request.Builder()
|
||||
.url(BASE_URL + "updateFCMToken.php?user_id=" + id + "&user_key=" + key)
|
||||
.url(BASE_URL + "update.php?user_id=" + id + "&user_key=" + key)
|
||||
.build();
|
||||
|
||||
client.newCall(request).enqueue(new Callback() {
|
||||
@Override
|
||||
public void onFailure(Call call, IOException e) {
|
||||
Log.e("SC:update_2", e.toString());
|
||||
public void onFailure(Call call, IOException e)
|
||||
{
|
||||
handleError("update<1>", call, null, Str.Empty, true, e);
|
||||
SCNApp.showToast("Communication with server failed", 4000);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResponse(Call call, Response response) {
|
||||
try (ResponseBody responseBody = response.body()) {
|
||||
public void onResponse(Call call, Response response)
|
||||
{
|
||||
String r = Str.Empty;
|
||||
try (ResponseBody responseBody = response.body())
|
||||
{
|
||||
if (!response.isSuccessful())
|
||||
throw new IOException("Unexpected code " + response);
|
||||
if (responseBody == null) throw new IOException("No response");
|
||||
|
||||
String r = responseBody.string();
|
||||
r = responseBody.string();
|
||||
Log.d("Server::Response", request.url().toString()+"\n"+r);
|
||||
|
||||
JSONObject json = (JSONObject) new JSONTokener(r).nextValue();
|
||||
|
||||
if (!json_bool(json, "success")) {
|
||||
SCNApp.showToast(json_str(json, "message"), 4000);
|
||||
handleNonSuccess("update<2>", call, response, r);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -207,10 +214,16 @@ public class ServerCommunication
|
||||
SCNSettings.inst().save();
|
||||
|
||||
SCNApp.refreshAccountTab();
|
||||
} catch (Exception e) {
|
||||
Log.e("SC:update_2", e.toString());
|
||||
|
||||
handleSuccess("update<2>", call, response, r);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
handleError("update<2>", call, response, r, false, e);
|
||||
SCNApp.showToast("Communication with server failed", 4000);
|
||||
} finally {
|
||||
}
|
||||
finally
|
||||
{
|
||||
SCNApp.runOnUiThread(() -> {
|
||||
if (loader != null) loader.setVisibility(View.GONE);
|
||||
});
|
||||
@@ -220,8 +233,7 @@ public class ServerCommunication
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Log.e("SC:update_2", e.toString());
|
||||
SCNApp.showToast("Communication with server failed", 4000);
|
||||
handleError("update<2>", null, null, Str.Empty, false, e);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -236,21 +248,23 @@ public class ServerCommunication
|
||||
client.newCall(request).enqueue(new Callback() {
|
||||
@Override
|
||||
public void onFailure(Call call, IOException e) {
|
||||
Log.e("SC:info", e.toString());
|
||||
SCNApp.showToast("Communication with server failed", 4000);
|
||||
handleError("info", call, null, Str.Empty, true, e);
|
||||
SCNApp.runOnUiThread(() -> {
|
||||
if (loader != null) loader.setVisibility(View.GONE);
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResponse(Call call, Response response) {
|
||||
try (ResponseBody responseBody = response.body()) {
|
||||
public void onResponse(Call call, Response response)
|
||||
{
|
||||
String r = Str.Empty;
|
||||
try (ResponseBody responseBody = response.body())
|
||||
{
|
||||
if (!response.isSuccessful())
|
||||
throw new IOException("Unexpected code " + response);
|
||||
if (responseBody == null) throw new IOException("No response");
|
||||
|
||||
String r = responseBody.string();
|
||||
r = responseBody.string();
|
||||
Log.d("Server::Response", request.url().toString()+"\n"+r);
|
||||
|
||||
JSONObject json = (JSONObject) new JSONTokener(r).nextValue();
|
||||
@@ -258,6 +272,7 @@ public class ServerCommunication
|
||||
if (!json_bool(json, "success"))
|
||||
{
|
||||
SCNApp.showToast(json_str(json, "message"), 4000);
|
||||
handleNonSuccess("info", call, response, r);
|
||||
|
||||
int errid = json.optInt("errid", 0);
|
||||
|
||||
@@ -290,21 +305,23 @@ public class ServerCommunication
|
||||
|
||||
if (json_int(json, "unack_count")>0) ServerCommunication.requery(id, key, loader);
|
||||
|
||||
} catch (Exception e) {
|
||||
Log.e("SC:info", e.toString());
|
||||
handleSuccess("info", call, response, r);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
handleError("info", call, response, r, false, e);
|
||||
SCNApp.showToast("Communication with server failed", 4000);
|
||||
} finally {
|
||||
SCNApp.runOnUiThread(() -> {
|
||||
if (loader != null) loader.setVisibility(View.GONE);
|
||||
});
|
||||
}
|
||||
finally
|
||||
{
|
||||
SCNApp.runOnUiThread(() -> { if (loader != null) loader.setVisibility(View.GONE); });
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Log.e("SC:info", e.toString());
|
||||
SCNApp.showToast("Communication with server failed", 4000);
|
||||
handleError("info", null, null, Str.Empty, false, e);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -319,21 +336,23 @@ public class ServerCommunication
|
||||
client.newCall(request).enqueue(new Callback() {
|
||||
@Override
|
||||
public void onFailure(Call call, IOException e) {
|
||||
Log.e("SC:requery", e.toString());
|
||||
SCNApp.showToast("Communication with server failed", 4000);
|
||||
handleError("requery", call, null, Str.Empty, true, e);
|
||||
SCNApp.runOnUiThread(() -> {
|
||||
if (loader != null) loader.setVisibility(View.GONE);
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResponse(Call call, Response response) {
|
||||
try (ResponseBody responseBody = response.body()) {
|
||||
public void onResponse(Call call, Response response)
|
||||
{
|
||||
String r = Str.Empty;
|
||||
try (ResponseBody responseBody = response.body())
|
||||
{
|
||||
if (!response.isSuccessful())
|
||||
throw new IOException("Unexpected code " + response);
|
||||
if (responseBody == null) throw new IOException("No response");
|
||||
|
||||
String r = responseBody.string();
|
||||
r = responseBody.string();
|
||||
Log.d("Server::Response", request.url().toString()+"\n"+r);
|
||||
|
||||
JSONObject json = (JSONObject) new JSONTokener(r).nextValue();
|
||||
@@ -341,6 +360,7 @@ public class ServerCommunication
|
||||
if (!json_bool(json, "success"))
|
||||
{
|
||||
SCNApp.showToast(json_str(json, "message"), 4000);
|
||||
handleNonSuccess("requery", call, response, r);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -359,10 +379,15 @@ public class ServerCommunication
|
||||
FBMService.recieveData(time, title, content, prio, scn_id, true);
|
||||
}
|
||||
|
||||
} catch (Exception e) {
|
||||
Log.e("SC:info", e.toString());
|
||||
handleSuccess("requery", call, response, r);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
handleError("requery", call, response, r, false, e);
|
||||
SCNApp.showToast("Communication with server failed", 4000);
|
||||
} finally {
|
||||
}
|
||||
finally
|
||||
{
|
||||
SCNApp.runOnUiThread(() -> {
|
||||
if (loader != null) loader.setVisibility(View.GONE);
|
||||
});
|
||||
@@ -372,8 +397,7 @@ public class ServerCommunication
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Log.e("SC:requery", e.toString());
|
||||
SCNApp.showToast("Communication with server failed", 4000);
|
||||
handleError("requery", null, null, Str.Empty, false, e);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -387,27 +411,31 @@ public class ServerCommunication
|
||||
.url(BASE_URL + "upgrade.php?user_id=" + id + "&user_key=" + key + "&pro=" + pro + "&pro_token=" + URLEncoder.encode(pro_token, "utf-8"))
|
||||
.build();
|
||||
|
||||
client.newCall(request).enqueue(new Callback() {
|
||||
client.newCall(request).enqueue(new Callback()
|
||||
{
|
||||
@Override
|
||||
public void onFailure(Call call, IOException e) {
|
||||
Log.e("SC:upgrade", e.toString());
|
||||
SCNApp.showToast("Communication with server failed", 4000);
|
||||
public void onFailure(Call call, IOException e)
|
||||
{
|
||||
handleError("upgrade", call, null, Str.Empty, true, e);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResponse(Call call, Response response) {
|
||||
try (ResponseBody responseBody = response.body()) {
|
||||
if (!response.isSuccessful())
|
||||
throw new IOException("Unexpected code " + response);
|
||||
public void onResponse(Call call, Response response)
|
||||
{
|
||||
String r = Str.Empty;
|
||||
try (ResponseBody responseBody = response.body())
|
||||
{
|
||||
if (!response.isSuccessful()) throw new IOException("Unexpected code " + response);
|
||||
if (responseBody == null) throw new IOException("No response");
|
||||
|
||||
String r = responseBody.string();
|
||||
r = responseBody.string();
|
||||
Log.d("Server::Response", request.url().toString()+"\n"+r);
|
||||
|
||||
JSONObject json = (JSONObject) new JSONTokener(r).nextValue();
|
||||
|
||||
if (!json_bool(json, "success")) {
|
||||
SCNApp.showToast(json_str(json, "message"), 4000);
|
||||
handleNonSuccess("upgrade", call, response, r);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -418,10 +446,15 @@ public class ServerCommunication
|
||||
SCNSettings.inst().save();
|
||||
|
||||
SCNApp.refreshAccountTab();
|
||||
} catch (Exception e) {
|
||||
Log.e("SC:upgrade", e.toString());
|
||||
SCNApp.showToast("Communication with server failed", 4000);
|
||||
} finally {
|
||||
|
||||
handleSuccess("upgrade", call, response, r);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
handleError("upgrade", call, response, r, false, e);
|
||||
}
|
||||
finally
|
||||
{
|
||||
SCNApp.runOnUiThread(() -> { if (loader != null) loader.setVisibility(View.GONE); });
|
||||
}
|
||||
}
|
||||
@@ -429,8 +462,7 @@ public class ServerCommunication
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
SCNApp.showToast("Communication with server failed", 4000);
|
||||
handleError("upgrade", null, null, Str.Empty, false, e);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -442,37 +474,47 @@ public class ServerCommunication
|
||||
.url(BASE_URL + "ack.php?user_id=" + id + "&user_key=" + key + "&scn_msg_id=" + msg_scn_id)
|
||||
.build();
|
||||
|
||||
client.newCall(request).enqueue(new Callback() {
|
||||
client.newCall(request).enqueue(new Callback()
|
||||
{
|
||||
@Override
|
||||
public void onFailure(Call call, IOException e) {
|
||||
Log.e("SC:ack", e.toString());
|
||||
public void onFailure(Call call, IOException e)
|
||||
{
|
||||
handleError("ack", call, null, Str.Empty, true, e);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResponse(Call call, Response response)
|
||||
{
|
||||
try (ResponseBody responseBody = response.body()) {
|
||||
String r = Str.Empty;
|
||||
try (ResponseBody responseBody = response.body())
|
||||
{
|
||||
if (!response.isSuccessful())
|
||||
throw new IOException("Unexpected code " + response);
|
||||
if (responseBody == null) throw new IOException("No response");
|
||||
|
||||
String r = responseBody.string();
|
||||
r = responseBody.string();
|
||||
Log.d("Server::Response", request.url().toString()+"\n"+r);
|
||||
|
||||
JSONObject json = (JSONObject) new JSONTokener(r).nextValue();
|
||||
|
||||
if (!json_bool(json, "success")) SCNApp.showToast(json_str(json, "message"), 4000);
|
||||
if (!json_bool(json, "success"))
|
||||
{
|
||||
SCNApp.showToast(json_str(json, "message"), 4000);
|
||||
handleNonSuccess("ack", call, response, r);
|
||||
}
|
||||
|
||||
} catch (Exception e) {
|
||||
Log.e("SC:ack", e.toString());
|
||||
SCNApp.showToast("Communication with server failed", 4000);
|
||||
handleSuccess("ack", call, response, r);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
handleError("ack", call, response, r, false, e);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Log.e("SC:ack", e.toString());
|
||||
handleError("ack", null, null, Str.Empty, false, e);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -487,21 +529,21 @@ public class ServerCommunication
|
||||
client.newCall(request).enqueue(new Callback() {
|
||||
@Override
|
||||
public void onFailure(Call call, IOException e) {
|
||||
Log.e("SC:expand", e.toString());
|
||||
SCNApp.showToast("Communication with server failed", 4000);
|
||||
SCNApp.runOnUiThread(() -> {
|
||||
if (loader != null) loader.setVisibility(View.GONE);
|
||||
});
|
||||
handleError("expand", call, null, Str.Empty, true, e);
|
||||
SCNApp.runOnUiThread(() -> { if (loader != null) loader.setVisibility(View.GONE); });
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResponse(Call call, Response response) {
|
||||
try (ResponseBody responseBody = response.body()) {
|
||||
public void onResponse(Call call, Response response)
|
||||
{
|
||||
String r = Str.Empty;
|
||||
try (ResponseBody responseBody = response.body())
|
||||
{
|
||||
if (!response.isSuccessful())
|
||||
throw new IOException("Unexpected code " + response);
|
||||
if (responseBody == null) throw new IOException("No response");
|
||||
|
||||
String r = responseBody.string();
|
||||
r = responseBody.string();
|
||||
Log.d("Server::Response", request.url().toString()+"\n"+r);
|
||||
|
||||
JSONObject json = (JSONObject) new JSONTokener(r).nextValue();
|
||||
@@ -509,6 +551,7 @@ public class ServerCommunication
|
||||
if (!json_bool(json, "success"))
|
||||
{
|
||||
SCNApp.showToast(json_str(json, "message"), 4000);
|
||||
handleNonSuccess("expand", call, response, r);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -522,21 +565,22 @@ public class ServerCommunication
|
||||
|
||||
okResult.invoke(title, content, prio, time, scn_id);
|
||||
|
||||
} catch (Exception e) {
|
||||
Log.e("SC:expand", e.toString());
|
||||
SCNApp.showToast("Communication with server failed", 4000);
|
||||
} finally {
|
||||
SCNApp.runOnUiThread(() -> {
|
||||
if (loader != null) loader.setVisibility(View.GONE);
|
||||
});
|
||||
handleSuccess("expand", call, response, r);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
handleError("expand", call, response, r, false, e);
|
||||
}
|
||||
finally
|
||||
{
|
||||
SCNApp.runOnUiThread(() -> { if (loader != null) loader.setVisibility(View.GONE); });
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Log.e("SC:expand", e.toString());
|
||||
SCNApp.showToast("Communication with server failed", 4000);
|
||||
handleError("expand", null, null, Str.Empty, false, e);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -564,4 +608,79 @@ public class ServerCommunication
|
||||
{
|
||||
return o.getString(key);
|
||||
}
|
||||
|
||||
private static void handleSuccess(String source, Call call, Response resp, String respBody)
|
||||
{
|
||||
Log.d("SC:"+source, respBody);
|
||||
|
||||
try
|
||||
{
|
||||
Instant i = Instant.now();
|
||||
String s = source;
|
||||
String u = call.request().url().toString();
|
||||
int rc = resp.code();
|
||||
String r = respBody;
|
||||
LogLevel l = LogLevel.INFO;
|
||||
|
||||
SingleQuery q = new SingleQuery(l, i, s, u, r, rc, "SUCCESS");
|
||||
QueryLog.inst().add(q);
|
||||
}
|
||||
catch (Exception e2)
|
||||
{
|
||||
Log.e("SC:HandleSuccess", e2.toString());
|
||||
}
|
||||
}
|
||||
|
||||
private static void handleNonSuccess(String source, Call call, Response resp, String respBody)
|
||||
{
|
||||
Log.d("SC:"+source, respBody);
|
||||
|
||||
try
|
||||
{
|
||||
Instant i = Instant.now();
|
||||
String s = source;
|
||||
String u = call.request().url().toString();
|
||||
int rc = resp.code();
|
||||
String r = respBody;
|
||||
LogLevel l = LogLevel.WARN;
|
||||
|
||||
SingleQuery q = new SingleQuery(l, i, s, u, r, rc, "NON-SUCCESS");
|
||||
QueryLog.inst().add(q);
|
||||
}
|
||||
catch (Exception e2)
|
||||
{
|
||||
Log.e("SC:HandleSuccess", e2.toString());
|
||||
}
|
||||
}
|
||||
|
||||
private static void handleError(String source, Call call, Response resp, String respBody, boolean isio, Exception e)
|
||||
{
|
||||
Log.e("SC:"+source, e.toString());
|
||||
|
||||
if (isio)
|
||||
{
|
||||
SCNApp.showToast("Can't connect to server", 3000);
|
||||
}
|
||||
else
|
||||
{
|
||||
SCNApp.showToast("Communication with server failed", 4000);
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
Instant i = Instant.now();
|
||||
String s = source;
|
||||
String u = (call==null)?Str.Empty:call.request().url().toString();
|
||||
int rc = (resp==null)?-1:resp.code();
|
||||
String r = respBody;
|
||||
LogLevel l = isio?LogLevel.WARN:LogLevel.ERROR;
|
||||
|
||||
SingleQuery q = new SingleQuery(l, i, s, u, r, rc, e.toString());
|
||||
QueryLog.inst().add(q);
|
||||
}
|
||||
catch (Exception e2)
|
||||
{
|
||||
Log.e("SC:HandleError", e2.toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -0,0 +1,82 @@
|
||||
package com.blackforestbytes.simplecloudnotifier.model;
|
||||
|
||||
import android.content.SharedPreferences;
|
||||
import android.os.BaseBundle;
|
||||
import android.os.Bundle;
|
||||
|
||||
import com.blackforestbytes.simplecloudnotifier.lib.string.Str;
|
||||
|
||||
import org.joda.time.Instant;
|
||||
|
||||
public class SingleQuery
|
||||
{
|
||||
public final Instant Timestamp;
|
||||
|
||||
public final LogLevel Level;
|
||||
public final String Name;
|
||||
public final String URL;
|
||||
public final String Response;
|
||||
public final int ResponseCode;
|
||||
public final String ExceptionString;
|
||||
|
||||
public SingleQuery(LogLevel l, Instant i, String n, String u, String r, int rc, String e)
|
||||
{
|
||||
Level=l;
|
||||
Timestamp=i;
|
||||
Name=n;
|
||||
URL=u;
|
||||
Response=r;
|
||||
ResponseCode=rc;
|
||||
ExceptionString=e;
|
||||
}
|
||||
|
||||
public void save(SharedPreferences.Editor e, String base)
|
||||
{
|
||||
e.putInt(base+".Level", Level.asInt());
|
||||
e.putLong(base+".Timestamp", Timestamp.getMillis());
|
||||
e.putString(base+".Name", Name);
|
||||
e.putString(base+".URL", URL);
|
||||
e.putString(base+".Response", Response);
|
||||
e.putInt(base+".ResponseCode", ResponseCode);
|
||||
e.putString(base+".ExceptionString", ExceptionString);
|
||||
}
|
||||
|
||||
public void save(BaseBundle e, String base)
|
||||
{
|
||||
e.putInt(base+".Level", Level.asInt());
|
||||
e.putLong(base+".Timestamp", Timestamp.getMillis());
|
||||
e.putString(base+".Name", Name);
|
||||
e.putString(base+".URL", URL);
|
||||
e.putString(base+".Response", Response);
|
||||
e.putInt(base+".ResponseCode", ResponseCode);
|
||||
e.putString(base+".ExceptionString", ExceptionString);
|
||||
}
|
||||
|
||||
public static SingleQuery load(SharedPreferences e, String base)
|
||||
{
|
||||
return new SingleQuery
|
||||
(
|
||||
LogLevel.fromInt(e.getInt(base+".Level", 0)),
|
||||
new Instant(e.getLong(base+".Timestamp", 0)),
|
||||
e.getString(base+".Name", Str.Empty),
|
||||
e.getString(base+".URL", Str.Empty),
|
||||
e.getString(base+".Response", Str.Empty),
|
||||
e.getInt(base+".ResponseCode", -1),
|
||||
e.getString(base+".ExceptionString", Str.Empty)
|
||||
);
|
||||
}
|
||||
|
||||
public static SingleQuery load(BaseBundle e, String base)
|
||||
{
|
||||
return new SingleQuery
|
||||
(
|
||||
LogLevel.fromInt(e.getInt(base+".Level", 0)),
|
||||
new Instant(e.getLong(base+".Timestamp", 0)),
|
||||
e.getString(base+".Name", Str.Empty),
|
||||
e.getString(base+".URL", Str.Empty),
|
||||
e.getString(base+".Response", Str.Empty),
|
||||
e.getInt(base+".ResponseCode", -1),
|
||||
e.getString(base+".ExceptionString", Str.Empty)
|
||||
);
|
||||
}
|
||||
}
|
@@ -4,16 +4,21 @@ import android.util.Log;
|
||||
import android.widget.Toast;
|
||||
|
||||
import com.blackforestbytes.simplecloudnotifier.SCNApp;
|
||||
import com.blackforestbytes.simplecloudnotifier.lib.datatypes.Tuple4;
|
||||
import com.blackforestbytes.simplecloudnotifier.lib.datatypes.Tuple5;
|
||||
import com.blackforestbytes.simplecloudnotifier.lib.string.Str;
|
||||
import com.blackforestbytes.simplecloudnotifier.model.CMessage;
|
||||
import com.blackforestbytes.simplecloudnotifier.model.CMessageList;
|
||||
import com.blackforestbytes.simplecloudnotifier.model.LogLevel;
|
||||
import com.blackforestbytes.simplecloudnotifier.model.PriorityEnum;
|
||||
import com.blackforestbytes.simplecloudnotifier.model.QueryLog;
|
||||
import com.blackforestbytes.simplecloudnotifier.model.SCNSettings;
|
||||
import com.blackforestbytes.simplecloudnotifier.model.ServerCommunication;
|
||||
import com.blackforestbytes.simplecloudnotifier.model.SingleQuery;
|
||||
import com.google.firebase.messaging.FirebaseMessagingService;
|
||||
import com.google.firebase.messaging.RemoteMessage;
|
||||
|
||||
import org.joda.time.Instant;
|
||||
import org.json.JSONObject;
|
||||
|
||||
public class FBMService extends FirebaseMessagingService
|
||||
{
|
||||
@Override
|
||||
@@ -42,6 +47,10 @@ public class FBMService extends FirebaseMessagingService
|
||||
long scn_id = Long.parseLong(remoteMessage.getData().get("scn_msg_id"));
|
||||
boolean trimmed = Boolean.parseBoolean(remoteMessage.getData().get("trimmed"));
|
||||
|
||||
|
||||
SingleQuery q = new SingleQuery(LogLevel.INFO, Instant.now(), "FBM<recieve>", Str.Empty, new JSONObject(remoteMessage.getData()).toString(), 0, "SUCCESS");
|
||||
QueryLog.inst().add(q);
|
||||
|
||||
if (trimmed)
|
||||
{
|
||||
ServerCommunication.expand(SCNSettings.inst().user_id, SCNSettings.inst().user_key, scn_id, null, (i1, i2, i3, i4, i5) -> recieveData(i4, i1, i2, i3, i5, false));
|
||||
|
@@ -2,23 +2,37 @@ package com.blackforestbytes.simplecloudnotifier.service;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.Context;
|
||||
import android.content.SharedPreferences;
|
||||
import android.util.Log;
|
||||
import android.widget.Toast;
|
||||
|
||||
import com.android.billingclient.api.BillingClient;
|
||||
import com.android.billingclient.api.BillingClientStateListener;
|
||||
import com.android.billingclient.api.BillingFlowParams;
|
||||
import com.android.billingclient.api.BillingResult;
|
||||
import com.android.billingclient.api.Purchase;
|
||||
import com.android.billingclient.api.PurchasesUpdatedListener;
|
||||
import com.android.billingclient.api.SkuDetails;
|
||||
import com.android.billingclient.api.SkuDetailsParams;
|
||||
import com.android.billingclient.api.SkuDetailsResponseListener;
|
||||
import com.blackforestbytes.simplecloudnotifier.SCNApp;
|
||||
import com.blackforestbytes.simplecloudnotifier.lib.datatypes.Tuple2;
|
||||
import com.blackforestbytes.simplecloudnotifier.lib.datatypes.Tuple3;
|
||||
import com.blackforestbytes.simplecloudnotifier.lib.lambda.Func0to0;
|
||||
import com.blackforestbytes.simplecloudnotifier.lib.string.Str;
|
||||
import com.blackforestbytes.simplecloudnotifier.model.SCNSettings;
|
||||
import com.blackforestbytes.simplecloudnotifier.view.MainActivity;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.Dictionary;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import static androidx.constraintlayout.widget.Constraints.TAG;
|
||||
@@ -45,18 +59,72 @@ public class IABService implements PurchasesUpdatedListener
|
||||
}
|
||||
}
|
||||
|
||||
public enum SimplePurchaseState { YES, NO, UNINITIALIZED }
|
||||
|
||||
private BillingClient client;
|
||||
private boolean isServiceConnected;
|
||||
private final List<Purchase> purchases = new ArrayList<>();
|
||||
private boolean _isInitialized = false;
|
||||
|
||||
private final Map<String, Boolean> _localCache= new HashMap<>();
|
||||
|
||||
public IABService(Context c)
|
||||
{
|
||||
_isInitialized = false;
|
||||
|
||||
loadCache();
|
||||
|
||||
client = BillingClient
|
||||
.newBuilder(c)
|
||||
.setListener(this)
|
||||
.build();
|
||||
|
||||
startServiceConnection(this::queryPurchases, false);
|
||||
startServiceConnection(this::querySkuDetails, false);
|
||||
}
|
||||
|
||||
public void reloadPrefs()
|
||||
{
|
||||
loadCache();
|
||||
}
|
||||
|
||||
private void loadCache()
|
||||
{
|
||||
_localCache.clear();
|
||||
SharedPreferences sharedPref = SCNApp.getContext().getSharedPreferences("IAB", Context.MODE_PRIVATE);
|
||||
int count = sharedPref.getInt("c", 0);
|
||||
for (int i=0; i < count; i++)
|
||||
{
|
||||
String k = sharedPref.getString("["+i+"]->key", null);
|
||||
boolean v = sharedPref.getBoolean("["+i+"]->value", false);
|
||||
if (k==null)continue;
|
||||
_localCache.put(k, v);
|
||||
}
|
||||
}
|
||||
|
||||
private void saveCache()
|
||||
{
|
||||
SharedPreferences sharedPref = SCNApp.getContext().getSharedPreferences("IAB", Context.MODE_PRIVATE);
|
||||
SharedPreferences.Editor editor= sharedPref.edit();
|
||||
|
||||
editor.putInt("c", _localCache.size());
|
||||
int i = 0;
|
||||
for (Map.Entry<String, Boolean> e : _localCache.entrySet())
|
||||
{
|
||||
editor.putString("["+i+"]->key", e.getKey());
|
||||
editor.putBoolean("["+i+"]->value", e.getValue());
|
||||
i++;
|
||||
}
|
||||
editor.apply();
|
||||
}
|
||||
|
||||
@SuppressWarnings("ConstantConditions")
|
||||
private synchronized void updateCache(String k, boolean v)
|
||||
{
|
||||
if (_localCache.containsKey(k) && _localCache.get(k)==v) return;
|
||||
|
||||
_localCache.put(k, v);
|
||||
saveCache();
|
||||
}
|
||||
|
||||
public void queryPurchases()
|
||||
@@ -67,14 +135,16 @@ public class IABService implements PurchasesUpdatedListener
|
||||
Purchase.PurchasesResult purchasesResult = client.queryPurchases(BillingClient.SkuType.INAPP);
|
||||
Log.i(TAG, "Querying purchases elapsed time: " + (System.currentTimeMillis() - time) + "ms");
|
||||
|
||||
if (purchasesResult.getResponseCode() == BillingClient.BillingResponse.OK)
|
||||
if (purchasesResult.getResponseCode() == BillingClient.BillingResponseCode.OK)
|
||||
{
|
||||
for (Purchase p : purchasesResult.getPurchasesList())
|
||||
for (Purchase p : Objects.requireNonNull(purchasesResult.getPurchasesList()))
|
||||
{
|
||||
handlePurchase(p);
|
||||
handlePurchase(p, false);
|
||||
}
|
||||
|
||||
boolean newProMode = getPurchaseCached(IAB_PRO_MODE) != null;
|
||||
_isInitialized = true;
|
||||
|
||||
boolean newProMode = getPurchaseCachedSimple(IAB_PRO_MODE);
|
||||
if (newProMode != SCNSettings.inst().promode_local)
|
||||
{
|
||||
refreshProModeListener();
|
||||
@@ -89,20 +159,39 @@ public class IABService implements PurchasesUpdatedListener
|
||||
executeServiceRequest(queryToExecute, false);
|
||||
}
|
||||
|
||||
public void querySkuDetails() {
|
||||
}
|
||||
|
||||
public void purchase(Activity a, String id)
|
||||
{
|
||||
Func0to0 queryRequest = () -> {
|
||||
// Query the purchase async
|
||||
SkuDetailsParams.Builder params = SkuDetailsParams.newBuilder();
|
||||
params.setSkusList(Collections.singletonList(id)).setType(BillingClient.SkuType.INAPP);
|
||||
client.querySkuDetailsAsync(params.build(), (billingResult, skuDetailsList) ->
|
||||
{
|
||||
if (billingResult.getResponseCode() != BillingClient.BillingResponseCode.OK || skuDetailsList == null || skuDetailsList.size() != 1)
|
||||
{
|
||||
SCNApp.showToast("Could not find product", Toast.LENGTH_SHORT);
|
||||
return;
|
||||
}
|
||||
|
||||
executeServiceRequest(() ->
|
||||
{
|
||||
BillingFlowParams flowParams = BillingFlowParams
|
||||
.newBuilder()
|
||||
.setSku(id)
|
||||
.setType(BillingClient.SkuType.INAPP) // SkuType.SUB for subscription
|
||||
.setSkuDetails(skuDetailsList.get(0))
|
||||
.build();
|
||||
client.launchBillingFlow(a, flowParams);
|
||||
}, true);
|
||||
});
|
||||
};
|
||||
executeServiceRequest(queryRequest, false);
|
||||
|
||||
}
|
||||
|
||||
private void executeServiceRequest(Func0to0 runnable, final boolean userRequest) {
|
||||
private void executeServiceRequest(Func0to0 runnable, final boolean userRequest)
|
||||
{
|
||||
if (isServiceConnected)
|
||||
{
|
||||
runnable.invoke();
|
||||
@@ -124,34 +213,37 @@ public class IABService implements PurchasesUpdatedListener
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPurchasesUpdated(int responseCode, @Nullable List<Purchase> purchases)
|
||||
public void onPurchasesUpdated(@NonNull BillingResult billingResult, @Nullable List<Purchase> purchases)
|
||||
{
|
||||
if (responseCode == BillingClient.BillingResponse.OK && purchases != null)
|
||||
if (billingResult.getResponseCode() == BillingClient.BillingResponseCode.OK && purchases != null)
|
||||
{
|
||||
for (Purchase purchase : purchases)
|
||||
{
|
||||
handlePurchase(purchase);
|
||||
handlePurchase(purchase, true);
|
||||
}
|
||||
}
|
||||
else if (responseCode == BillingClient.BillingResponse.ITEM_ALREADY_OWNED && purchases != null)
|
||||
else if (billingResult.getResponseCode() == BillingClient.BillingResponseCode.ITEM_ALREADY_OWNED && purchases != null)
|
||||
{
|
||||
for (Purchase purchase : purchases)
|
||||
{
|
||||
handlePurchase(purchase);
|
||||
handlePurchase(purchase, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void handlePurchase(Purchase purchase)
|
||||
private void handlePurchase(Purchase purchase, boolean triggerUpdate)
|
||||
{
|
||||
Log.d(TAG, "Got a verified purchase: " + purchase);
|
||||
|
||||
purchases.add(purchase);
|
||||
|
||||
refreshProModeListener();
|
||||
if (triggerUpdate) refreshProModeListener();
|
||||
|
||||
updateCache(purchase.getSku(), true);
|
||||
}
|
||||
|
||||
private void refreshProModeListener() {
|
||||
private void refreshProModeListener()
|
||||
{
|
||||
MainActivity ma = SCNApp.getMainActivity();
|
||||
if (ma != null) ma.adpTabs.tab3.updateProState();
|
||||
if (ma != null) ma.adpTabs.tab1.updateProState();
|
||||
@@ -163,9 +255,9 @@ public class IABService implements PurchasesUpdatedListener
|
||||
client.startConnection(new BillingClientStateListener()
|
||||
{
|
||||
@Override
|
||||
public void onBillingSetupFinished(@BillingClient.BillingResponse int billingResponseCode)
|
||||
public void onBillingSetupFinished(@NonNull BillingResult billingResult)
|
||||
{
|
||||
if (billingResponseCode == BillingClient.BillingResponse.OK)
|
||||
if (billingResult.getResponseCode() == BillingClient.BillingResponseCode.OK)
|
||||
{
|
||||
isServiceConnected = true;
|
||||
if (executeOnSuccess != null) executeOnSuccess.invoke();
|
||||
@@ -183,13 +275,31 @@ public class IABService implements PurchasesUpdatedListener
|
||||
});
|
||||
}
|
||||
|
||||
public Purchase getPurchaseCached(String id)
|
||||
public boolean getPurchaseCachedSimple(String id)
|
||||
{
|
||||
for (Purchase p : purchases)
|
||||
{
|
||||
if (Str.equals(p.getSku(), id)) return p;
|
||||
return getPurchaseCachedExtended(id).Item1;
|
||||
}
|
||||
|
||||
return null;
|
||||
@SuppressWarnings("ConstantConditions")
|
||||
public Tuple3<Boolean, Boolean, String> getPurchaseCachedExtended(String id)
|
||||
{
|
||||
// <state, initialized, token>
|
||||
|
||||
if (!_isInitialized)
|
||||
{
|
||||
if (_localCache.containsKey(id) && _localCache.get(id)) return new Tuple3<>(true, false, Str.Empty);
|
||||
}
|
||||
|
||||
for (Purchase p : purchases)
|
||||
{
|
||||
if (Str.equals(p.getSku(), id))
|
||||
{
|
||||
updateCache(id, true);
|
||||
return new Tuple3<>(true, true, p.getPurchaseToken());
|
||||
}
|
||||
}
|
||||
|
||||
updateCache(id, false);
|
||||
return new Tuple3<>(false, true, Str.Empty);
|
||||
}
|
||||
}
|
||||
|
@@ -65,7 +65,8 @@ public class NotificationService
|
||||
channel0.setDescription("Push notifications from the server with low priority.\nGo to the in-app settings to configure ringtone, volume and vibrations");
|
||||
channel0.setSound(null, null);
|
||||
channel0.setVibrationPattern(null);
|
||||
channel0.setLightColor(Color.BLUE);
|
||||
channel0.setLightColor(Color.CYAN);
|
||||
channel0.enableLights(true);
|
||||
notifman.createNotificationChannel(channel0);
|
||||
}
|
||||
}
|
||||
@@ -77,7 +78,8 @@ public class NotificationService
|
||||
channel1.setDescription("Push notifications from the server with low priority.\nGo to the in-app settings to configure ringtone, volume and vibrations");
|
||||
channel1.setSound(null, null);
|
||||
channel1.setVibrationPattern(null);
|
||||
channel1.setLightColor(Color.BLUE);
|
||||
channel1.setLightColor(Color.CYAN);
|
||||
channel1.enableLights(true);
|
||||
notifman.createNotificationChannel(channel1);
|
||||
}
|
||||
}
|
||||
@@ -85,11 +87,13 @@ public class NotificationService
|
||||
NotificationChannel channel2 = notifman.getNotificationChannel(CHANNEL_P2_ID);
|
||||
if (channel2 == null)
|
||||
{
|
||||
channel2 = new NotificationChannel(CHANNEL_P1_ID, "Push notifications (high priority)", NotificationManager.IMPORTANCE_DEFAULT);
|
||||
channel2 = new NotificationChannel(CHANNEL_P2_ID, "Push notifications (high priority)", NotificationManager.IMPORTANCE_DEFAULT);
|
||||
channel2.setDescription("Push notifications from the server with low priority.\nGo to the in-app settings to configure ringtone, volume and vibrations");
|
||||
channel2.setSound(null, null);
|
||||
channel2.setVibrationPattern(null);
|
||||
channel2.setLightColor(Color.BLUE);
|
||||
channel2.setLockscreenVisibility(Notification.VISIBILITY_PRIVATE);
|
||||
channel2.setLightColor(Color.CYAN);
|
||||
channel2.enableLights(true);
|
||||
notifman.createNotificationChannel(channel2);
|
||||
}
|
||||
}
|
||||
@@ -115,9 +119,9 @@ public class NotificationService
|
||||
{
|
||||
Vibrator v = (Vibrator) SCNApp.getContext().getSystemService(Context.VIBRATOR_SERVICE);
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
v.vibrate(VibrationEffect.createOneShot(1500, VibrationEffect.DEFAULT_AMPLITUDE));
|
||||
v.vibrate(VibrationEffect.createOneShot(500, VibrationEffect.DEFAULT_AMPLITUDE));
|
||||
} else {
|
||||
v.vibrate(1500);
|
||||
v.vibrate(500);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -225,10 +229,10 @@ public class NotificationService
|
||||
if (msg.Priority == PriorityEnum.NORMAL) mBuilder.setPriority(NotificationCompat.PRIORITY_DEFAULT);
|
||||
if (msg.Priority == PriorityEnum.HIGH) mBuilder.setPriority(NotificationCompat.PRIORITY_HIGH);
|
||||
|
||||
Intent intnt_click = new Intent(SCNApp.getContext(), BroadcastReceiverService.class);
|
||||
intnt_click.putExtra(BroadcastReceiverService.ID_KEY, BroadcastReceiverService.NOTIF_SHOW_MAIN);
|
||||
PendingIntent pi = PendingIntent.getBroadcast(ctxt, 0, intnt_click, 0);
|
||||
Intent intent = new Intent(ctxt, MainActivity.class);
|
||||
PendingIntent pi = PendingIntent.getActivity(ctxt, 0, intent, 0);
|
||||
mBuilder.setContentIntent(pi);
|
||||
|
||||
NotificationManager mNotificationManager = (NotificationManager) ctxt.getSystemService(Context.NOTIFICATION_SERVICE);
|
||||
if (mNotificationManager == null) return;
|
||||
|
||||
@@ -254,7 +258,7 @@ public class NotificationService
|
||||
if (ns.EnableVibration)
|
||||
{
|
||||
Vibrator v = (Vibrator) SCNApp.getContext().getSystemService(Context.VIBRATOR_SERVICE);
|
||||
v.vibrate(VibrationEffect.createOneShot(1500, VibrationEffect.DEFAULT_AMPLITUDE));
|
||||
v.vibrate(VibrationEffect.createOneShot(500, VibrationEffect.DEFAULT_AMPLITUDE));
|
||||
}
|
||||
|
||||
//if (ns.EnableLED) { } // no LED in Android-O -- configure via Channel
|
||||
|
@@ -0,0 +1,56 @@
|
||||
package com.blackforestbytes.simplecloudnotifier.util;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.res.Resources;
|
||||
import android.content.res.TypedArray;
|
||||
import android.util.AttributeSet;
|
||||
import android.util.TypedValue;
|
||||
import android.widget.ScrollView;
|
||||
|
||||
import com.blackforestbytes.simplecloudnotifier.R;
|
||||
|
||||
public class MaxHeightScrollView extends ScrollView
|
||||
{
|
||||
public int maxHeight = Integer.MAX_VALUE;//dp
|
||||
|
||||
public MaxHeightScrollView(Context context)
|
||||
{
|
||||
super(context);
|
||||
}
|
||||
|
||||
public MaxHeightScrollView(Context context, AttributeSet attrs)
|
||||
{
|
||||
super(context, attrs);
|
||||
|
||||
TypedArray a = context.getTheme().obtainStyledAttributes(attrs, R.styleable.MaxHeightScrollView, 0, 0);
|
||||
try {
|
||||
maxHeight = a.getInteger(R.styleable.MaxHeightScrollView_maxHeightOverride, Integer.MAX_VALUE);
|
||||
} finally {
|
||||
a.recycle();
|
||||
}
|
||||
}
|
||||
|
||||
public MaxHeightScrollView(Context context, AttributeSet attrs, int defStyleAttr)
|
||||
{
|
||||
super(context, attrs, defStyleAttr);
|
||||
|
||||
TypedArray a = context.getTheme().obtainStyledAttributes(attrs, R.styleable.MaxHeightScrollView, 0, 0);
|
||||
try {
|
||||
maxHeight = a.getInteger(R.styleable.MaxHeightScrollView_maxHeightOverride, Integer.MAX_VALUE);
|
||||
} finally {
|
||||
a.recycle();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
|
||||
{
|
||||
heightMeasureSpec = MeasureSpec.makeMeasureSpec(dpToPx(getResources(), maxHeight), MeasureSpec.AT_MOST);
|
||||
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
|
||||
}
|
||||
|
||||
private int dpToPx(Resources res, int dp)
|
||||
{
|
||||
return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, res.getDisplayMetrics());
|
||||
}
|
||||
}
|
@@ -0,0 +1,25 @@
|
||||
package com.blackforestbytes.simplecloudnotifier.util;
|
||||
|
||||
import android.text.Editable;
|
||||
import android.text.TextWatcher;
|
||||
|
||||
public abstract class TextChangedListener<T> implements TextWatcher {
|
||||
private T target;
|
||||
|
||||
public TextChangedListener(T target) {
|
||||
this.target = target;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void beforeTextChanged(CharSequence s, int start, int count, int after) {}
|
||||
|
||||
@Override
|
||||
public void onTextChanged(CharSequence s, int start, int before, int count) {}
|
||||
|
||||
@Override
|
||||
public void afterTextChanged(Editable s) {
|
||||
this.onTextChanged(target, s);
|
||||
}
|
||||
|
||||
public abstract void onTextChanged(T target, Editable s);
|
||||
}
|
@@ -1,14 +1,23 @@
|
||||
package com.blackforestbytes.simplecloudnotifier.view;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.SharedPreferences;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.util.Log;
|
||||
import android.view.View;
|
||||
import android.widget.RelativeLayout;
|
||||
import android.widget.Toast;
|
||||
|
||||
import com.blackforestbytes.simplecloudnotifier.R;
|
||||
import com.blackforestbytes.simplecloudnotifier.SCNApp;
|
||||
import com.blackforestbytes.simplecloudnotifier.model.CMessageList;
|
||||
import com.blackforestbytes.simplecloudnotifier.model.QueryLog;
|
||||
import com.blackforestbytes.simplecloudnotifier.model.SCNSettings;
|
||||
import com.blackforestbytes.simplecloudnotifier.service.IABService;
|
||||
import com.blackforestbytes.simplecloudnotifier.service.NotificationService;
|
||||
import com.blackforestbytes.simplecloudnotifier.view.debug.QueryLogActivity;
|
||||
import com.google.android.material.tabs.TabLayout;
|
||||
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
@@ -16,6 +25,12 @@ import androidx.appcompat.widget.Toolbar;
|
||||
import androidx.viewpager.widget.PagerAdapter;
|
||||
import androidx.viewpager.widget.ViewPager;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.ObjectInputStream;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
public class MainActivity extends AppCompatActivity
|
||||
{
|
||||
public TabAdapter adpTabs;
|
||||
@@ -24,6 +39,8 @@ public class MainActivity extends AppCompatActivity
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState)
|
||||
{
|
||||
QueryLog.inst();
|
||||
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.activity_main);
|
||||
|
||||
@@ -33,6 +50,7 @@ public class MainActivity extends AppCompatActivity
|
||||
layoutRoot = findViewById(R.id.layoutRoot);
|
||||
|
||||
Toolbar toolbar = findViewById(R.id.toolbar);
|
||||
toolbar.setOnClickListener(this::onToolbackClicked);
|
||||
setSupportActionBar(toolbar);
|
||||
|
||||
ViewPager viewPager = findViewById(R.id.pager);
|
||||
@@ -61,7 +79,7 @@ public class MainActivity extends AppCompatActivity
|
||||
|
||||
SCNApp.register(this);
|
||||
IABService.startup(this);
|
||||
SCNSettings.inst().work(this);
|
||||
SCNSettings.inst().work(this, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -81,4 +99,126 @@ public class MainActivity extends AppCompatActivity
|
||||
CMessageList.inst().fullSave();
|
||||
IABService.inst().destroy();
|
||||
}
|
||||
|
||||
private int clickCount = 0;
|
||||
private long lastClick = 0;
|
||||
private void onToolbackClicked(View v)
|
||||
{
|
||||
long now = System.currentTimeMillis();
|
||||
if (now - lastClick > 200) clickCount=0;
|
||||
clickCount++;
|
||||
lastClick = now;
|
||||
|
||||
if (clickCount == 4) startActivity(new Intent(this, QueryLogActivity.class));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
|
||||
super.onActivityResult(requestCode, resultCode, data);
|
||||
if(requestCode == 1991 && resultCode == RESULT_OK)
|
||||
{
|
||||
Uri uri = data.getData(); //The uri with the location of the file
|
||||
|
||||
Context ctxt = this;
|
||||
|
||||
try
|
||||
{
|
||||
ObjectInputStream stream = new ObjectInputStream(getContentResolver().openInputStream(uri));
|
||||
|
||||
Map<String, ?> d1 = (Map<String, ?>)stream.readObject();
|
||||
Map<String, ?> d2 = (Map<String, ?>)stream.readObject();
|
||||
Map<String, ?> d3 = (Map<String, ?>)stream.readObject();
|
||||
Map<String, ?> d4 = (Map<String, ?>)stream.readObject();
|
||||
|
||||
stream.close();
|
||||
|
||||
runOnUiThread(() ->
|
||||
{
|
||||
|
||||
SharedPreferences.Editor e1 = ctxt.getSharedPreferences("Config", Context.MODE_PRIVATE).edit();
|
||||
SharedPreferences.Editor e2 = ctxt.getSharedPreferences("IAB", Context.MODE_PRIVATE).edit();
|
||||
SharedPreferences.Editor e3 = ctxt.getSharedPreferences("CMessageList", Context.MODE_PRIVATE).edit();
|
||||
SharedPreferences.Editor e4 = ctxt.getSharedPreferences("QueryLog", Context.MODE_PRIVATE).edit();
|
||||
|
||||
e1.clear();
|
||||
for (Map.Entry<String, ?> entry : d1.entrySet())
|
||||
{
|
||||
if (entry.getValue() instanceof String) e1.putString(entry.getKey(), (String)entry.getValue());
|
||||
if (entry.getValue() instanceof Boolean) e1.putBoolean(entry.getKey(), (Boolean)entry.getValue());
|
||||
if (entry.getValue() instanceof Float) e1.putFloat(entry.getKey(), (Float)entry.getValue());
|
||||
if (entry.getValue() instanceof Integer) e1.putInt(entry.getKey(), (Integer)entry.getValue());
|
||||
if (entry.getValue() instanceof Long) e1.putLong(entry.getKey(), (Long)entry.getValue());
|
||||
if (entry.getValue() instanceof Set<?>) e1.putStringSet(entry.getKey(), (Set<String>)entry.getValue());
|
||||
}
|
||||
|
||||
e2.clear();
|
||||
for (Map.Entry<String, ?> entry : d2.entrySet())
|
||||
{
|
||||
if (entry.getValue() instanceof String) e2.putString(entry.getKey(), (String)entry.getValue());
|
||||
if (entry.getValue() instanceof Boolean) e2.putBoolean(entry.getKey(), (Boolean)entry.getValue());
|
||||
if (entry.getValue() instanceof Float) e2.putFloat(entry.getKey(), (Float)entry.getValue());
|
||||
if (entry.getValue() instanceof Integer) e2.putInt(entry.getKey(), (Integer)entry.getValue());
|
||||
if (entry.getValue() instanceof Long) e2.putLong(entry.getKey(), (Long)entry.getValue());
|
||||
if (entry.getValue() instanceof Set<?>) e2.putStringSet(entry.getKey(), (Set<String>)entry.getValue());
|
||||
}
|
||||
|
||||
e2.clear();
|
||||
for (Map.Entry<String, ?> entry : d3.entrySet())
|
||||
{
|
||||
if (entry.getValue() instanceof String) e3.putString(entry.getKey(), (String)entry.getValue());
|
||||
if (entry.getValue() instanceof Boolean) e3.putBoolean(entry.getKey(), (Boolean)entry.getValue());
|
||||
if (entry.getValue() instanceof Float) e3.putFloat(entry.getKey(), (Float)entry.getValue());
|
||||
if (entry.getValue() instanceof Integer) e3.putInt(entry.getKey(), (Integer)entry.getValue());
|
||||
if (entry.getValue() instanceof Long) e3.putLong(entry.getKey(), (Long)entry.getValue());
|
||||
if (entry.getValue() instanceof Set<?>) e3.putStringSet(entry.getKey(), (Set<String>)entry.getValue());
|
||||
}
|
||||
|
||||
e4.clear();
|
||||
for (Map.Entry<String, ?> entry : d4.entrySet())
|
||||
{
|
||||
if (entry.getValue() instanceof String) e4.putString(entry.getKey(), (String)entry.getValue());
|
||||
if (entry.getValue() instanceof Boolean) e4.putBoolean(entry.getKey(), (Boolean)entry.getValue());
|
||||
if (entry.getValue() instanceof Float) e4.putFloat(entry.getKey(), (Float)entry.getValue());
|
||||
if (entry.getValue() instanceof Integer) e4.putInt(entry.getKey(), (Integer)entry.getValue());
|
||||
if (entry.getValue() instanceof Long) e4.putLong(entry.getKey(), (Long)entry.getValue());
|
||||
if (entry.getValue() instanceof Set<?>) e4.putStringSet(entry.getKey(), (Set<String>)entry.getValue());
|
||||
}
|
||||
|
||||
e1.apply();
|
||||
e2.apply();
|
||||
e3.apply();
|
||||
e4.apply();
|
||||
|
||||
|
||||
SCNSettings.inst().reloadPrefs();
|
||||
IABService.inst().reloadPrefs();
|
||||
CMessageList.inst().reloadPrefs();
|
||||
QueryLog.inst().reloadPrefs();
|
||||
|
||||
|
||||
Toolbar toolbar = findViewById(R.id.toolbar);
|
||||
setSupportActionBar(toolbar);
|
||||
|
||||
ViewPager viewPager = findViewById(R.id.pager);
|
||||
PagerAdapter adapter = adpTabs = new TabAdapter(getSupportFragmentManager());
|
||||
viewPager.setAdapter(adapter);
|
||||
|
||||
TabLayout tabLayout = findViewById(R.id.tab_layout);
|
||||
tabLayout.setupWithViewPager(viewPager);
|
||||
|
||||
|
||||
SCNSettings.inst().work(this, true);
|
||||
|
||||
SCNApp.showToast("Backup imported", Toast.LENGTH_LONG);
|
||||
|
||||
finish();
|
||||
});
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Log.e("Import:Err", e.toString());
|
||||
SCNApp.showToast("Import failed", Toast.LENGTH_LONG);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -1,5 +1,6 @@
|
||||
package com.blackforestbytes.simplecloudnotifier.view;
|
||||
|
||||
import android.content.Intent;
|
||||
import android.graphics.Color;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
@@ -9,8 +10,11 @@ import android.widget.RelativeLayout;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.blackforestbytes.simplecloudnotifier.R;
|
||||
import com.blackforestbytes.simplecloudnotifier.SCNApp;
|
||||
import com.blackforestbytes.simplecloudnotifier.model.CMessage;
|
||||
import com.blackforestbytes.simplecloudnotifier.model.CMessageList;
|
||||
import com.blackforestbytes.simplecloudnotifier.model.SCNSettings;
|
||||
import com.google.android.material.button.MaterialButton;
|
||||
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.util.Collections;
|
||||
@@ -53,7 +57,7 @@ public class MessageAdapter extends RecyclerView.Adapter
|
||||
{
|
||||
CMessage msg = CMessageList.inst().tryGetFromBack(position);
|
||||
MessagePresenter view = (MessagePresenter) holder;
|
||||
view.setMessage(msg);
|
||||
view.setMessage(msg, position);
|
||||
|
||||
viewHolders.put(view, true);
|
||||
}
|
||||
@@ -110,7 +114,11 @@ public class MessageAdapter extends RecyclerView.Adapter
|
||||
public RelativeLayout viewForeground;
|
||||
public RelativeLayout viewBackground;
|
||||
|
||||
public MaterialButton btnShare;
|
||||
public MaterialButton btnDelete;
|
||||
|
||||
private CMessage data;
|
||||
private int datapos;
|
||||
|
||||
MessagePresenter(View itemView)
|
||||
{
|
||||
@@ -121,6 +129,8 @@ public class MessageAdapter extends RecyclerView.Adapter
|
||||
ivPriority = itemView.findViewById(R.id.ivPriority);
|
||||
viewForeground = itemView.findViewById(R.id.layoutFront);
|
||||
viewBackground = itemView.findViewById(R.id.layoutBack);
|
||||
btnShare = itemView.findViewById(R.id.btnShare);
|
||||
btnDelete = itemView.findViewById(R.id.btnDelete);
|
||||
|
||||
itemView.setOnClickListener(this);
|
||||
tvTimestamp.setOnClickListener(this);
|
||||
@@ -128,9 +138,22 @@ public class MessageAdapter extends RecyclerView.Adapter
|
||||
tvMessage.setOnClickListener(this);
|
||||
ivPriority.setOnClickListener(this);
|
||||
viewForeground.setOnClickListener(this);
|
||||
|
||||
btnShare.setOnClickListener(v ->
|
||||
{
|
||||
if (data == null) return;
|
||||
Intent sharingIntent = new Intent(android.content.Intent.ACTION_SEND);
|
||||
sharingIntent.setType("text/plain");
|
||||
sharingIntent.putExtra(android.content.Intent.EXTRA_SUBJECT, data.Title);
|
||||
sharingIntent.putExtra(android.content.Intent.EXTRA_TEXT, data.Content);
|
||||
SCNApp.getMainActivity().startActivity(Intent.createChooser(sharingIntent, "Share message"));
|
||||
|
||||
});
|
||||
btnDelete.setOnClickListener(v -> { if (data != null) SCNApp.getMainActivity().adpTabs.tab1.deleteMessage(datapos); });
|
||||
|
||||
}
|
||||
|
||||
void setMessage(CMessage msg)
|
||||
void setMessage(CMessage msg, int pos)
|
||||
{
|
||||
tvTimestamp.setText(msg.formatTimestamp());
|
||||
tvTitle.setText(msg.Title);
|
||||
@@ -155,21 +178,49 @@ public class MessageAdapter extends RecyclerView.Adapter
|
||||
}
|
||||
|
||||
data = msg;
|
||||
datapos = pos;
|
||||
|
||||
if (msg.IsExpandedInAdapter) expand(true); else collapse(true);
|
||||
}
|
||||
|
||||
private void expand(boolean force)
|
||||
{
|
||||
if (data != null && data.IsExpandedInAdapter && !force) return;
|
||||
if (data != null) data.IsExpandedInAdapter = true;
|
||||
if (tvMessage != null) tvMessage.setMaxLines(9999);
|
||||
if (btnDelete != null) btnDelete.setVisibility(View.VISIBLE);
|
||||
if (btnShare != null) btnShare.setVisibility(View.VISIBLE);
|
||||
|
||||
}
|
||||
|
||||
private int norm(int i) { return (i<=0)?0:((i>9999)?9999:i); }
|
||||
|
||||
private void collapse(boolean force)
|
||||
{
|
||||
if (data != null && !data.IsExpandedInAdapter && !force) return;
|
||||
if (data != null) data.IsExpandedInAdapter = false;
|
||||
if (tvMessage != null) tvMessage.setMaxLines(norm(SCNSettings.inst().PreviewLineCount));
|
||||
if (btnDelete != null) btnDelete.setVisibility(View.GONE);
|
||||
if (btnShare != null) btnShare.setVisibility(View.GONE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClick(View v)
|
||||
{
|
||||
if (data.IsExpandedInAdapter)
|
||||
{
|
||||
collapse(false);
|
||||
return;
|
||||
}
|
||||
|
||||
for (MessagePresenter holder : MessageAdapter.this.viewHolders.keySet())
|
||||
{
|
||||
if (holder == null) continue;
|
||||
if (holder == this) continue;
|
||||
if (holder.tvMessage == null) continue;
|
||||
if (holder.tvMessage.getMaxLines() == 6) continue;
|
||||
holder.tvMessage.setMaxLines(6);
|
||||
holder.collapse(false);
|
||||
}
|
||||
|
||||
tvMessage.setMaxLines(9999);
|
||||
expand(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -58,7 +58,7 @@ public class NotificationsFragment extends Fragment implements MessageAdapterTou
|
||||
|
||||
public void updateProState()
|
||||
{
|
||||
if (adView != null) adView.setVisibility(IABService.inst().getPurchaseCached(IABService.IAB_PRO_MODE) != null ? View.GONE : View.VISIBLE);
|
||||
if (adView != null) adView.setVisibility(IABService.inst().getPurchaseCachedSimple(IABService.IAB_PRO_MODE) ? View.GONE : View.VISIBLE);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -66,9 +66,15 @@ public class NotificationsFragment extends Fragment implements MessageAdapterTou
|
||||
{
|
||||
if (viewHolder instanceof MessageAdapter.MessagePresenter)
|
||||
{
|
||||
final int deletedIndex = viewHolder.getAdapterPosition();
|
||||
deleteMessage(viewHolder.getAdapterPosition());
|
||||
}
|
||||
}
|
||||
|
||||
final CMessage deletedItem = adpMessages.removeItem(viewHolder.getAdapterPosition());
|
||||
public void deleteMessage(int pos)
|
||||
{
|
||||
final int deletedIndex = pos;
|
||||
|
||||
final CMessage deletedItem = adpMessages.removeItem(pos);
|
||||
String name = deletedItem.Title;
|
||||
|
||||
Snackbar snackbar = Snackbar.make(SCNApp.getMainActivity().layoutRoot, name + " removed", Snackbar.LENGTH_LONG);
|
||||
@@ -76,5 +82,9 @@ public class NotificationsFragment extends Fragment implements MessageAdapterTou
|
||||
snackbar.setActionTextColor(Color.YELLOW);
|
||||
snackbar.show();
|
||||
}
|
||||
|
||||
public void updateDeleteSwipeEnabled()
|
||||
{
|
||||
if (touchHelper != null) touchHelper.updateEnabled();
|
||||
}
|
||||
}
|
||||
|
@@ -1,15 +1,15 @@
|
||||
package com.blackforestbytes.simplecloudnotifier.view;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.graphics.Color;
|
||||
import android.media.AudioAttributes;
|
||||
import android.media.AudioManager;
|
||||
import android.media.MediaPlayer;
|
||||
import android.media.Ringtone;
|
||||
import android.media.RingtoneManager;
|
||||
import android.net.Uri;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.text.Editable;
|
||||
import android.util.Log;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
@@ -17,6 +17,7 @@ import android.view.ViewGroup;
|
||||
import android.widget.AdapterView;
|
||||
import android.widget.ArrayAdapter;
|
||||
import android.widget.Button;
|
||||
import android.widget.EditText;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.SeekBar;
|
||||
import android.widget.Spinner;
|
||||
@@ -24,21 +25,26 @@ import android.widget.Switch;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
|
||||
import com.android.billingclient.api.Purchase;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.core.content.FileProvider;
|
||||
import androidx.fragment.app.Fragment;
|
||||
|
||||
import com.blackforestbytes.simplecloudnotifier.R;
|
||||
import com.blackforestbytes.simplecloudnotifier.SCNApp;
|
||||
import com.blackforestbytes.simplecloudnotifier.lib.android.ThreadUtils;
|
||||
import com.blackforestbytes.simplecloudnotifier.lib.lambda.FI;
|
||||
import com.blackforestbytes.simplecloudnotifier.lib.string.Str;
|
||||
import com.blackforestbytes.simplecloudnotifier.model.SCNSettings;
|
||||
import com.blackforestbytes.simplecloudnotifier.service.IABService;
|
||||
import com.blackforestbytes.simplecloudnotifier.util.TextChangedListener;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.ObjectOutputStream;
|
||||
import java.util.Map;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.fragment.app.Fragment;
|
||||
import top.defaults.colorpicker.ColorPickerPopup;
|
||||
import xyz.aprildown.ultimatemusicpicker.MusicPickerListener;
|
||||
import xyz.aprildown.ultimatemusicpicker.UltimateMusicPicker;
|
||||
@@ -51,6 +57,7 @@ public class SettingsFragment extends Fragment implements MusicPickerListener
|
||||
private TextView prefUpgradeAccount_msg;
|
||||
private TextView prefUpgradeAccount_info;
|
||||
private Switch prefEnableDeleteSwipe;
|
||||
private EditText prefPreviewLineCount;
|
||||
|
||||
private Switch prefMsgLowEnableSound;
|
||||
private TextView prefMsgLowRingtone_value;
|
||||
@@ -88,6 +95,9 @@ public class SettingsFragment extends Fragment implements MusicPickerListener
|
||||
private SeekBar prefMsgHighVolume;
|
||||
private ImageView prefMsgHighVolumeTest;
|
||||
|
||||
private Button prefBtnImport;
|
||||
private Button prefBtnExport;
|
||||
|
||||
private int musicPickerSwitch = -1;
|
||||
|
||||
private MediaPlayer[] mPlayers = new MediaPlayer[3];
|
||||
@@ -117,6 +127,7 @@ public class SettingsFragment extends Fragment implements MusicPickerListener
|
||||
prefUpgradeAccount_msg = v.findViewById(R.id.prefUpgradeAccount2);
|
||||
prefUpgradeAccount_info = v.findViewById(R.id.prefUpgradeAccount_info);
|
||||
prefEnableDeleteSwipe = v.findViewById(R.id.prefEnableDeleteSwipe);
|
||||
prefPreviewLineCount = v.findViewById(R.id.prefPreviewLineCount);
|
||||
|
||||
prefMsgLowEnableSound = v.findViewById(R.id.prefMsgLowEnableSound);
|
||||
prefMsgLowRingtone_value = v.findViewById(R.id.prefMsgLowRingtone_value);
|
||||
@@ -153,8 +164,16 @@ public class SettingsFragment extends Fragment implements MusicPickerListener
|
||||
prefMsgHighForceVolume = v.findViewById(R.id.prefMsgHighForceVolume);
|
||||
prefMsgHighVolume = v.findViewById(R.id.prefMsgHighVolume);
|
||||
prefMsgHighVolumeTest = v.findViewById(R.id.btnHighVolumeTest);
|
||||
|
||||
prefBtnExport = v.findViewById(R.id.prefExport);
|
||||
prefBtnImport = v.findViewById(R.id.prefImport);
|
||||
|
||||
ArrayAdapter<Integer> plcsa = new ArrayAdapter<>(v.getContext(), android.R.layout.simple_spinner_item, SCNSettings.CHOOSABLE_CACHE_SIZES);
|
||||
plcsa.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
|
||||
prefLocalCacheSize.setAdapter(plcsa);
|
||||
}
|
||||
|
||||
@SuppressLint("SetTextI18n")
|
||||
private void updateUI()
|
||||
{
|
||||
SCNSettings s = SCNSettings.inst();
|
||||
@@ -163,15 +182,13 @@ public class SettingsFragment extends Fragment implements MusicPickerListener
|
||||
|
||||
if (prefAppEnabled.isChecked() != s.Enabled) prefAppEnabled.setChecked(s.Enabled);
|
||||
if (prefEnableDeleteSwipe.isChecked() != s.EnableDeleteSwipe) prefEnableDeleteSwipe.setChecked(s.EnableDeleteSwipe);
|
||||
if (!prefPreviewLineCount.getText().toString().equals(Integer.toString(s.PreviewLineCount))) prefPreviewLineCount.setText(Integer.toString(s.PreviewLineCount));
|
||||
|
||||
prefUpgradeAccount.setVisibility( SCNSettings.inst().promode_local ? View.GONE : View.VISIBLE);
|
||||
prefUpgradeAccount_info.setVisibility(SCNSettings.inst().promode_local ? View.GONE : View.VISIBLE);
|
||||
prefUpgradeAccount_msg.setVisibility( SCNSettings.inst().promode_local ? View.VISIBLE : View.GONE );
|
||||
|
||||
ArrayAdapter<Integer> plcsa = new ArrayAdapter<>(c, android.R.layout.simple_spinner_item, SCNSettings.CHOOSABLE_CACHE_SIZES);
|
||||
plcsa.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
|
||||
prefLocalCacheSize.setAdapter(plcsa);
|
||||
prefLocalCacheSize.setSelection(getCacheSizeIndex(s.LocalCacheSize));
|
||||
if (prefLocalCacheSize.getSelectedItemPosition() != getCacheSizeIndex(s.LocalCacheSize)) prefLocalCacheSize.setSelection(getCacheSizeIndex(s.LocalCacheSize));
|
||||
|
||||
if (prefMsgLowEnableSound.isChecked() != s.PriorityLow.EnableSound) prefMsgLowEnableSound.setChecked(s.PriorityLow.EnableSound);
|
||||
if (!prefMsgLowRingtone_value.getText().equals(s.PriorityLow.SoundName)) prefMsgLowRingtone_value.setText(s.PriorityLow.SoundName);
|
||||
@@ -219,6 +236,12 @@ public class SettingsFragment extends Fragment implements MusicPickerListener
|
||||
|
||||
prefAppEnabled.setOnCheckedChangeListener((a,b) -> { boolean prev=s.Enabled; s.Enabled=b; saveAndUpdate(); updateEnabled(prev, b); });
|
||||
prefEnableDeleteSwipe.setOnCheckedChangeListener((a,b) -> { s.EnableDeleteSwipe=b; saveAndUpdate(); });
|
||||
prefPreviewLineCount.addTextChangedListener(new TextChangedListener<EditText>(prefPreviewLineCount) {
|
||||
@Override
|
||||
public void onTextChanged(EditText target, Editable ed) {
|
||||
if (!ed.toString().isEmpty()) try { s.PreviewLineCount=Integer.parseInt(ed.toString()); saveAndUpdate(); } catch (Exception e) { /* */ }
|
||||
}
|
||||
});
|
||||
|
||||
prefLocalCacheSize.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener()
|
||||
{
|
||||
@@ -231,6 +254,9 @@ public class SettingsFragment extends Fragment implements MusicPickerListener
|
||||
|
||||
prefUpgradeAccount.setOnClickListener(a -> onUpgradeAccount());
|
||||
|
||||
prefBtnExport.setOnClickListener(a -> onExport());
|
||||
prefBtnImport.setOnClickListener(a -> onImport());
|
||||
|
||||
prefMsgLowEnableSound.setOnCheckedChangeListener((a,b) -> { s.PriorityLow.EnableSound=b; saveAndUpdate(); });
|
||||
prefMsgLowRingtone_container.setOnClickListener(a -> chooseRingtoneLow());
|
||||
prefMsgLowRepeatSound.setOnCheckedChangeListener((a,b) -> { s.PriorityLow.RepeatSound=b; saveAndUpdate(); });
|
||||
@@ -262,6 +288,55 @@ public class SettingsFragment extends Fragment implements MusicPickerListener
|
||||
prefMsgHighVolumeTest.setOnClickListener((v) -> { if (s.PriorityHigh.ForceVolume) playTestSound(2, prefMsgHighVolumeTest, s.PriorityHigh.SoundSource, s.PriorityHigh.ForceVolumeValue); });
|
||||
}
|
||||
|
||||
private void onExport()
|
||||
{
|
||||
Context ctxt = getContext();
|
||||
if (ctxt == null) return;
|
||||
|
||||
try
|
||||
{
|
||||
File outputDir = ctxt.getCacheDir(); // context being the Activity pointer
|
||||
File outputFile = File.createTempFile("scn_export_", ".dat", outputDir);
|
||||
|
||||
ObjectOutputStream output = new ObjectOutputStream(new FileOutputStream(outputFile));
|
||||
|
||||
Map<String, ?> d1 = ctxt.getSharedPreferences("Config", Context.MODE_PRIVATE).getAll();
|
||||
Map<String, ?> d2 = ctxt.getSharedPreferences("IAB", Context.MODE_PRIVATE).getAll();
|
||||
Map<String, ?> d3 = ctxt.getSharedPreferences("CMessageList", Context.MODE_PRIVATE).getAll();
|
||||
Map<String, ?> d4 = ctxt.getSharedPreferences("QueryLog", Context.MODE_PRIVATE).getAll();
|
||||
|
||||
output.writeObject(d1);
|
||||
output.writeObject(d2);
|
||||
output.writeObject(d3);
|
||||
output.writeObject(d4);
|
||||
|
||||
Intent intent = new Intent(Intent.ACTION_SEND);
|
||||
|
||||
Uri uri = FileProvider.getUriForFile(ctxt, "com.blackforestbytes.simplecloudnotifier.fileprovider", outputFile);
|
||||
intent.putExtra(Intent.EXTRA_STREAM, uri);
|
||||
intent.setType("*/*");
|
||||
intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
|
||||
|
||||
startActivity(Intent.createChooser(intent, "Export"));
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
Log.e("Export:Err", e.toString());
|
||||
SCNApp.showToast("Export failed", Toast.LENGTH_LONG);
|
||||
}
|
||||
}
|
||||
|
||||
private void onImport()
|
||||
{
|
||||
SCNApp.getMainActivity().setContentView(R.layout.activity_main);
|
||||
|
||||
Intent intent = new Intent()
|
||||
.setType("*/*")
|
||||
.setAction(Intent.ACTION_GET_CONTENT);
|
||||
|
||||
((MainActivity)getActivity()).startActivityForResult(Intent.createChooser(intent, "Select a file"), 1991);
|
||||
}
|
||||
|
||||
private void updateEnabled(boolean prev, boolean now)
|
||||
{
|
||||
if (!prev && now)
|
||||
@@ -341,7 +416,7 @@ public class SettingsFragment extends Fragment implements MusicPickerListener
|
||||
{
|
||||
SCNSettings.inst().save();
|
||||
updateUI();
|
||||
SCNApp.getMainActivity().adpTabs.tab1.touchHelper.updateEnabled();
|
||||
SCNApp.getMainActivity().adpTabs.tab1.updateDeleteSwipeEnabled();
|
||||
}
|
||||
|
||||
private void onUpgradeAccount()
|
||||
@@ -351,11 +426,11 @@ public class SettingsFragment extends Fragment implements MusicPickerListener
|
||||
|
||||
public void updateProState()
|
||||
{
|
||||
Purchase p = IABService.inst().getPurchaseCached(IABService.IAB_PRO_MODE);
|
||||
boolean pmode = IABService.inst().getPurchaseCachedSimple(IABService.IAB_PRO_MODE);
|
||||
|
||||
if (prefUpgradeAccount != null) prefUpgradeAccount.setVisibility( p != null ? View.GONE : View.VISIBLE);
|
||||
if (prefUpgradeAccount_info != null) prefUpgradeAccount_info.setVisibility(p != null ? View.GONE : View.VISIBLE);
|
||||
if (prefUpgradeAccount_msg != null) prefUpgradeAccount_msg.setVisibility( p != null ? View.VISIBLE : View.GONE );
|
||||
if (prefUpgradeAccount != null) prefUpgradeAccount.setVisibility( pmode ? View.GONE : View.VISIBLE);
|
||||
if (prefUpgradeAccount_info != null) prefUpgradeAccount_info.setVisibility(pmode ? View.GONE : View.VISIBLE);
|
||||
if (prefUpgradeAccount_msg != null) prefUpgradeAccount_msg.setVisibility( pmode ? View.VISIBLE : View.GONE );
|
||||
}
|
||||
|
||||
private int getCacheSizeIndex(int value)
|
||||
|
@@ -0,0 +1,44 @@
|
||||
package com.blackforestbytes.simplecloudnotifier.view.debug;
|
||||
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
|
||||
import com.blackforestbytes.simplecloudnotifier.model.QueryLog;
|
||||
import com.blackforestbytes.simplecloudnotifier.model.SingleQuery;
|
||||
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
|
||||
import android.widget.ListView;
|
||||
|
||||
import com.blackforestbytes.simplecloudnotifier.R;
|
||||
|
||||
public class QueryLogActivity extends AppCompatActivity
|
||||
{
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState)
|
||||
{
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.activity_querylog);
|
||||
|
||||
ListView lvMain = findViewById(R.id.lvQueryList);
|
||||
SingleQuery[] arr = QueryLog.inst().get().toArray(new SingleQuery[0]);
|
||||
QueryLogAdapter a = new QueryLogAdapter(this, arr);
|
||||
lvMain.setAdapter(a);
|
||||
|
||||
lvMain.setOnItemClickListener((parent, view, position, id) ->
|
||||
{
|
||||
if (position >= 0 && position < arr.length)
|
||||
{
|
||||
Intent i = new Intent(QueryLogActivity.this, SingleQueryLogActivity.class);
|
||||
Bundle b = new Bundle();
|
||||
arr[position].save(b, "data");
|
||||
i.putExtra("query", b);
|
||||
startActivity(i);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,66 @@
|
||||
package com.blackforestbytes.simplecloudnotifier.view.debug;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.Color;
|
||||
import androidx.annotation.NonNull;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.ArrayAdapter;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.blackforestbytes.simplecloudnotifier.R;
|
||||
import com.blackforestbytes.simplecloudnotifier.model.SingleQuery;
|
||||
|
||||
import org.joda.time.format.DateTimeFormat;
|
||||
import org.joda.time.format.DateTimeFormatter;
|
||||
|
||||
public class QueryLogAdapter extends ArrayAdapter<SingleQuery>
|
||||
{
|
||||
public static DateTimeFormatter UI_FULLTIME_FORMATTER = DateTimeFormat.forPattern("HH:mm:ss");
|
||||
|
||||
public QueryLogAdapter(@NonNull Context context, @NonNull SingleQuery[] objects)
|
||||
{
|
||||
super(context, R.layout.adapter_querylog, objects);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public View getView(int position, View convertView, @NonNull ViewGroup parent)
|
||||
{
|
||||
View v = convertView;
|
||||
|
||||
if (v == null) {
|
||||
LayoutInflater vi;
|
||||
vi = LayoutInflater.from(getContext());
|
||||
v = vi.inflate(R.layout.adapter_querylog, parent, false);
|
||||
}
|
||||
|
||||
SingleQuery p = getItem(position);
|
||||
|
||||
if (p != null)
|
||||
{
|
||||
TextView tt1 = v.findViewById(R.id.list_item_debuglogrow_time);
|
||||
if (tt1 != null) tt1.setText(p.Timestamp.toString(UI_FULLTIME_FORMATTER));
|
||||
if (tt1 != null) tt1.setTextColor(Color.BLACK);
|
||||
|
||||
TextView tt2 = v.findViewById(R.id.list_item_debuglogrow_level);
|
||||
if (tt2 != null) tt2.setText(p.Level.toUIString());
|
||||
if (tt2 != null) tt2.setTextColor(Color.BLACK);
|
||||
|
||||
TextView tt3 = v.findViewById(R.id.list_item_debuglogrow_info);
|
||||
if (tt3 != null) tt3.setText("");
|
||||
if (tt3 != null) tt3.setTextColor(Color.BLUE);
|
||||
|
||||
TextView tt4 = v.findViewById(R.id.list_item_debuglogrow_id);
|
||||
if (tt4 != null) tt4.setText(p.Name);
|
||||
if (tt4 != null) tt4.setTextColor(p.Level.getColor());
|
||||
|
||||
TextView tt5 = v.findViewById(R.id.list_item_debuglogrow_message);
|
||||
if (tt5 != null) tt5.setText(p.ExceptionString.length()> 40 ? p.ExceptionString.substring(0, 40-3)+"..." : p.ExceptionString);
|
||||
if (tt5 != null) tt5.setTextColor(p.Level.getColor());
|
||||
}
|
||||
|
||||
return v;
|
||||
}
|
||||
}
|
@@ -0,0 +1,38 @@
|
||||
package com.blackforestbytes.simplecloudnotifier.view.debug;
|
||||
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.os.Bundle;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.blackforestbytes.simplecloudnotifier.R;
|
||||
import com.blackforestbytes.simplecloudnotifier.lib.string.CompactJsonFormatter;
|
||||
import com.blackforestbytes.simplecloudnotifier.model.SingleQuery;
|
||||
|
||||
import org.joda.time.format.DateTimeFormat;
|
||||
import org.joda.time.format.DateTimeFormatter;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
public class SingleQueryLogActivity extends AppCompatActivity
|
||||
{
|
||||
@Override
|
||||
@SuppressLint("SetTextI18n")
|
||||
protected void onCreate(Bundle savedInstanceState)
|
||||
{
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.activity_singlequerylog);
|
||||
|
||||
SingleQuery q = SingleQuery.load(getIntent().getBundleExtra("query"), "data");
|
||||
|
||||
this.<TextView>findViewById(R.id.tvQL_Timestamp).setText(q.Timestamp.toString(DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss")));
|
||||
this.<TextView>findViewById(R.id.tvQL_Level).setText(q.Level.toUIString());
|
||||
this.<TextView>findViewById(R.id.tvQL_Level).setTextColor(q.Level.getColor());
|
||||
this.<TextView>findViewById(R.id.tvQL_Name).setText(q.Name);
|
||||
this.<TextView>findViewById(R.id.tvQL_URL).setText(q.URL.replace("?", "\r\n?").replace("&", "\r\n&"));
|
||||
this.<TextView>findViewById(R.id.tvQL_Response).setText(CompactJsonFormatter.formatJSON(q.Response, 999));
|
||||
this.<TextView>findViewById(R.id.tvQL_ResponseCode).setText(Integer.toString(q.ResponseCode));
|
||||
this.<TextView>findViewById(R.id.tvQL_ExceptionString).setText(q.ExceptionString);
|
||||
}
|
||||
}
|
@@ -0,0 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle" >
|
||||
<solid android:color="@android:color/white" />
|
||||
<stroke android:width="1dip" android:color="#888888"/>
|
||||
</shape>
|
10
android/app/src/main/res/drawable/ic_share_small.xml
Normal file
10
android/app/src/main/res/drawable/ic_share_small.xml
Normal file
@@ -0,0 +1,10 @@
|
||||
<vector
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="12sp"
|
||||
android:height="12sp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M18,16.08c-0.76,0 -1.44,0.3 -1.96,0.77L8.91,12.7c0.05,-0.23 0.09,-0.46 0.09,-0.7s-0.04,-0.47 -0.09,-0.7l7.05,-4.11c0.54,0.5 1.25,0.81 2.04,0.81 1.66,0 3,-1.34 3,-3s-1.34,-3 -3,-3 -3,1.34 -3,3c0,0.24 0.04,0.47 0.09,0.7L8.04,9.81C7.5,9.31 6.79,9 6,9c-1.66,0 -3,1.34 -3,3s1.34,3 3,3c0.79,0 1.5,-0.31 2.04,-0.81l7.12,4.16c-0.05,0.21 -0.08,0.43 -0.08,0.65 0,1.61 1.31,2.92 2.92,2.92 1.61,0 2.92,-1.31 2.92,-2.92s-1.31,-2.92 -2.92,-2.92z"/>
|
||||
</vector>
|
16
android/app/src/main/res/drawable/ic_trash_small.xml
Normal file
16
android/app/src/main/res/drawable/ic_trash_small.xml
Normal file
@@ -0,0 +1,16 @@
|
||||
<vector
|
||||
android:height="12sp"
|
||||
android:width="12sp"
|
||||
android:viewportHeight="53"
|
||||
android:viewportWidth="53"
|
||||
xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
|
||||
<path
|
||||
android:fillColor="#FFFFFF"
|
||||
android:pathData="M42.943,6H33.5V3c0,-1.654 -1.346,-3 -3,-3h-8c-1.654,0 -3,1.346 -3,3v3h-9.443C8.096,6 6.5,7.596 6.5,9.557V14h2h36h2V9.557C46.5,7.596 44.904,6 42.943,6zM31.5,6h-10V3c0,-0.552 0.449,-1 1,-1h8c0.551,0 1,0.448 1,1V6z"/>
|
||||
|
||||
<path
|
||||
android:fillColor="#FFFFFF"
|
||||
android:pathData="M8.5,49.271C8.5,51.327 10.173,53 12.229,53h28.541c2.057,0 3.729,-1.673 3.729,-3.729V16h-36V49.271z"/>
|
||||
|
||||
</vector>
|
@@ -1,31 +1,31 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<RelativeLayout
|
||||
android:id="@+id/layoutRoot"
|
||||
<RelativeLayout android:id="@+id/layoutRoot"
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
tools:showIn="@layout/activity_main">
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||
|
||||
<androidx.appcompat.widget.Toolbar
|
||||
android:id="@+id/toolbar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignParentTop="true"
|
||||
app:titleTextColor="@color/colorOnPrimary"
|
||||
android:background="?attr/colorPrimary"
|
||||
android:elevation="6dp"
|
||||
android:minHeight="?attr/actionBarSize"
|
||||
android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar" />
|
||||
android:minHeight="?attr/actionBarSize" />
|
||||
|
||||
<com.google.android.material.tabs.TabLayout
|
||||
android:id="@+id/tab_layout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_below="@+id/toolbar"
|
||||
app:titleTextColor="@color/colorOnPrimary"
|
||||
app:tabTextColor="@color/colorOnPrimary"
|
||||
app:tabSelectedTextColor="@color/colorSecondary"
|
||||
android:background="?attr/colorPrimary"
|
||||
android:elevation="6dp"
|
||||
android:minHeight="?attr/actionBarSize"
|
||||
android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"/>
|
||||
android:minHeight="?attr/actionBarSize" />
|
||||
|
||||
<androidx.viewpager.widget.ViewPager
|
||||
android:id="@+id/pager"
|
||||
|
13
android/app/src/main/res/layout/activity_querylog.xml
Normal file
13
android/app/src/main/res/layout/activity_querylog.xml
Normal file
@@ -0,0 +1,13 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<RelativeLayout
|
||||
android:id="@+id/layoutRoot"
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<ListView
|
||||
android:id="@+id/lvQueryList"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent" />
|
||||
|
||||
</RelativeLayout>
|
240
android/app/src/main/res/layout/activity_singlequerylog.xml
Normal file
240
android/app/src/main/res/layout/activity_singlequerylog.xml
Normal file
@@ -0,0 +1,240 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<LinearLayout
|
||||
android:padding="4sp"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<TextView
|
||||
android:textAlignment="center"
|
||||
android:textStyle="bold"
|
||||
android:layout_margin="2dip"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_width="match_parent"
|
||||
android:text="Server Query" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<TextView
|
||||
android:layout_margin="2dip"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_width="100dp"
|
||||
android:text="Timestamp" />
|
||||
|
||||
<com.blackforestbytes.simplecloudnotifier.util.MaxHeightScrollView
|
||||
app:maxHeightOverride="100"
|
||||
android:background="@drawable/simple_black_border"
|
||||
android:layout_margin="2dip"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:fillViewport="true">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tvQL_Timestamp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_width="match_parent"
|
||||
android:padding="1dip"
|
||||
android:textIsSelectable="true"
|
||||
android:text="" />
|
||||
|
||||
</com.blackforestbytes.simplecloudnotifier.util.MaxHeightScrollView>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<TextView
|
||||
android:layout_margin="2dip"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_width="100dp"
|
||||
android:text="Level" />
|
||||
|
||||
<com.blackforestbytes.simplecloudnotifier.util.MaxHeightScrollView
|
||||
app:maxHeightOverride="100"
|
||||
android:background="@drawable/simple_black_border"
|
||||
android:layout_margin="2dip"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:fillViewport="true">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tvQL_Level"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_width="match_parent"
|
||||
android:padding="1dip"
|
||||
android:textIsSelectable="true"
|
||||
android:text="" />
|
||||
|
||||
</com.blackforestbytes.simplecloudnotifier.util.MaxHeightScrollView>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<TextView
|
||||
android:layout_margin="2dip"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_width="100dp"
|
||||
android:text="Name" />
|
||||
|
||||
<com.blackforestbytes.simplecloudnotifier.util.MaxHeightScrollView
|
||||
app:maxHeightOverride="100"
|
||||
android:layout_margin="2dip"
|
||||
android:background="@drawable/simple_black_border"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:fillViewport="true">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tvQL_Name"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_width="match_parent"
|
||||
android:padding="1dip"
|
||||
android:textIsSelectable="true"
|
||||
android:text="" />
|
||||
|
||||
</com.blackforestbytes.simplecloudnotifier.util.MaxHeightScrollView>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<TextView
|
||||
android:layout_margin="2dip"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_width="100dp"
|
||||
android:text="URL" />
|
||||
|
||||
<com.blackforestbytes.simplecloudnotifier.util.MaxHeightScrollView
|
||||
app:maxHeightOverride="100"
|
||||
android:layout_margin="2dip"
|
||||
android:background="@drawable/simple_black_border"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:fillViewport="true">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tvQL_URL"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_width="match_parent"
|
||||
android:padding="1dip"
|
||||
android:textIsSelectable="true"
|
||||
android:text=""/>
|
||||
|
||||
</com.blackforestbytes.simplecloudnotifier.util.MaxHeightScrollView>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<TextView
|
||||
android:layout_margin="2dip"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_width="100dp"
|
||||
android:text="ResponeCode" />
|
||||
|
||||
<com.blackforestbytes.simplecloudnotifier.util.MaxHeightScrollView
|
||||
app:maxHeightOverride="64"
|
||||
android:layout_margin="2dip"
|
||||
android:background="@drawable/simple_black_border"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:fillViewport="true">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tvQL_ResponseCode"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_width="match_parent"
|
||||
android:padding="1dip"
|
||||
android:textIsSelectable="true"
|
||||
android:text="" />
|
||||
|
||||
</com.blackforestbytes.simplecloudnotifier.util.MaxHeightScrollView>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<TextView
|
||||
android:layout_margin="2dip"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_width="100dp"
|
||||
android:text="Response" />
|
||||
|
||||
|
||||
<com.blackforestbytes.simplecloudnotifier.util.MaxHeightScrollView
|
||||
app:maxHeightOverride="100"
|
||||
android:layout_margin="2dip"
|
||||
android:background="@drawable/simple_black_border"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:fillViewport="true">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tvQL_Response"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_width="match_parent"
|
||||
android:padding="1dip"
|
||||
android:textIsSelectable="true"
|
||||
android:text="" />
|
||||
|
||||
</com.blackforestbytes.simplecloudnotifier.util.MaxHeightScrollView>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<TextView
|
||||
android:layout_margin="2dip"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_width="100dp"
|
||||
android:text="Exception" />
|
||||
|
||||
<com.blackforestbytes.simplecloudnotifier.util.MaxHeightScrollView
|
||||
app:maxHeightOverride="100"
|
||||
android:layout_margin="2dip"
|
||||
android:background="@drawable/simple_black_border"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:fillViewport="true">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tvQL_ExceptionString"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_width="match_parent"
|
||||
android:padding="1dip"
|
||||
android:textIsSelectable="true"
|
||||
android:text="" />
|
||||
|
||||
</com.blackforestbytes.simplecloudnotifier.util.MaxHeightScrollView>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</FrameLayout>
|
50
android/app/src/main/res/layout/adapter_querylog.xml
Normal file
50
android/app/src/main/res/layout/adapter_querylog.xml
Normal file
@@ -0,0 +1,50 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:id="@+id/list_item_imagerow"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="horizontal" >
|
||||
|
||||
<LinearLayout
|
||||
android:orientation="vertical"
|
||||
android:layout_width="96dp"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/list_item_debuglogrow_time"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/list_item_debuglogrow_level"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/list_item_debuglogrow_info"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:orientation="vertical"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/list_item_debuglogrow_id"
|
||||
android:textStyle="bold"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/list_item_debuglogrow_message"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
|
||||
</LinearLayout>
|
@@ -198,19 +198,27 @@
|
||||
app:layout_constraintBottom_toTopOf="@+id/btnAccountReset"
|
||||
app:layout_constraintTop_toBottomOf="@+id/ic_img_quota" />
|
||||
|
||||
<Button
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/btnAccountReset"
|
||||
app:cornerRadius="0dp"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="8dp"
|
||||
android:layout_marginStart="4dp"
|
||||
android:layout_marginEnd="4dp"
|
||||
android:backgroundTint="#fa315b"
|
||||
android:text="@string/str_reset_account"
|
||||
app:layout_constraintBottom_toTopOf="@+id/btnClearLocalStorage" />
|
||||
|
||||
<Button
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/btnClearLocalStorage"
|
||||
app:cornerRadius="0dp"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Clear Messages"
|
||||
android:layout_marginStart="4dp"
|
||||
android:layout_marginEnd="4dp"
|
||||
android:backgroundTint="#607D8B"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
|
@@ -95,6 +95,46 @@
|
||||
android:layout_height="wrap_content"
|
||||
android:minHeight="48dp" />
|
||||
|
||||
<View
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="1dp"
|
||||
android:layout_marginBottom="2dp"
|
||||
android:layout_marginTop="2dp"
|
||||
android:background="#c0c0c0"/>
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:layout_marginStart="4dp"
|
||||
android:layout_marginEnd="4dp"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:minHeight="48dp">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tvPreviewLineCount"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/str_previewlinecount"
|
||||
android:textColor="#000"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toStartOf="@+id/prefPreviewLineCount"
|
||||
app:layout_constraintHorizontal_bias="0"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<EditText
|
||||
android:minWidth="64dp"
|
||||
android:id="@+id/prefPreviewLineCount"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:inputType="number"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
android:importantForAutofill="no"
|
||||
tools:ignore="LabelFor,UnusedAttribute" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
||||
<View
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="1dp"
|
||||
@@ -111,8 +151,10 @@
|
||||
android:gravity="center|center"
|
||||
android:minHeight="48dp">
|
||||
|
||||
<Button
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/prefUpgradeAccount"
|
||||
app:cornerRadius="0dp"
|
||||
android:backgroundTint="#4CAF50"
|
||||
android:text="@string/str_upgrade_account"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content" />
|
||||
@@ -763,6 +805,24 @@
|
||||
|
||||
</androidx.cardview.widget.CardView>
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/prefExport"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="12dp"
|
||||
app:cornerRadius="0dp"
|
||||
android:backgroundTint="#444444"
|
||||
android:text="@string/export_settings" />
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/prefImport"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="12dp"
|
||||
app:cornerRadius="0dp"
|
||||
android:backgroundTint="#666666"
|
||||
android:text="@string/import_settings" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</ScrollView>
|
||||
|
@@ -108,6 +108,43 @@
|
||||
android:paddingTop="3dp"
|
||||
android:contentDescription="@string/desc_priority_icon" />
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/btnShare"
|
||||
style="@style/Widget.MaterialComponents.Button.Icon"
|
||||
app:cornerRadius="0dp"
|
||||
app:icon="@drawable/ic_share_small"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="25dp"
|
||||
android:layout_marginEnd="8sp"
|
||||
android:insetTop="0dp"
|
||||
android:insetBottom="0dp"
|
||||
android:insetLeft="0dp"
|
||||
android:insetRight="0dp"
|
||||
android:textSize="12sp"
|
||||
card_view:layout_constraintTop_toBottomOf="@id/tvMessage"
|
||||
app:layout_constraintRight_toLeftOf="@id/btnDelete"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
android:backgroundTint="#03A9F4"
|
||||
android:text="Share" />
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/btnDelete"
|
||||
style="@style/Widget.MaterialComponents.Button.Icon"
|
||||
app:cornerRadius="0dp"
|
||||
app:icon="@drawable/ic_trash_small"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="25dp"
|
||||
android:insetTop="0dp"
|
||||
android:insetBottom="0dp"
|
||||
android:insetLeft="0dp"
|
||||
android:insetRight="0dp"
|
||||
android:textSize="12sp"
|
||||
card_view:layout_constraintTop_toBottomOf="@id/tvMessage"
|
||||
app:layout_constraintRight_toRightOf="parent"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
android:backgroundTint="#F44336"
|
||||
android:text="Delete"/>
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
||||
</androidx.cardview.widget.CardView>
|
||||
|
8
android/app/src/main/res/values/attrs.xml
Normal file
8
android/app/src/main/res/values/attrs.xml
Normal file
@@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
|
||||
<declare-styleable name="MaxHeightScrollView">
|
||||
<attr name="maxHeightOverride" format="integer" />
|
||||
</declare-styleable>
|
||||
|
||||
</resources>
|
@@ -6,6 +6,9 @@
|
||||
<color name="colorHeader">#3F51B5</color>
|
||||
<color name="colorHeaderForeground">#FFFFFF</color>
|
||||
|
||||
<color name="colorOnPrimary">#ecf0f1</color>
|
||||
<color name="colorSecondary">#FF5722</color>
|
||||
|
||||
<color name="colorBlack">#000</color>
|
||||
|
||||
<color name="bg_row_background">#fa315b</color>
|
||||
|
@@ -6,4 +6,5 @@
|
||||
<dimen name="padd_10">10dp</dimen>
|
||||
<dimen name="ic_delete">30dp</dimen>
|
||||
<dimen name="thumbnail">90dp</dimen>
|
||||
<dimen name="fab_margin">16dp</dimen>
|
||||
</resources>
|
@@ -30,9 +30,13 @@
|
||||
<string name="str_enable_vibration">Enable notification vibration</string>
|
||||
<string name="str_upgrade_account">Upgrade account</string>
|
||||
<string name="str_deleteswipe">Delete messages by swiping left</string>
|
||||
<string name="str_previewlinecount">Number of visibile lines in collapsed messages</string>
|
||||
<string name="str_promode">Thank you for supporting the app and using the pro mode</string>
|
||||
<string name="str_promode_info">Increase your daily quota, remove the ad banner and support the developer (that\'s me)</string>
|
||||
<string name="volume_icon">Volume icon</string>
|
||||
<string name="play_test_sound">Play test sound</string>
|
||||
<string name="delete">DELETE</string>
|
||||
<string name="title_activity_query_log">QueryLogActivity</string>
|
||||
<string name="import_settings">Import settings</string>
|
||||
<string name="export_settings">Export settings</string>
|
||||
</resources>
|
||||
|
@@ -1,13 +1,20 @@
|
||||
<resources>
|
||||
|
||||
<!-- Base application theme. -->
|
||||
<style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
|
||||
<style name="AppTheme" parent="Theme.MaterialComponents.Light.NoActionBar">
|
||||
<!-- your app branding color for the app bar -->
|
||||
<item name="colorPrimary">#3F51B5</item>
|
||||
|
||||
<!-- darker variant for the status bar and contextual app bars -->
|
||||
<item name="colorPrimaryDark">#303F9F</item>
|
||||
|
||||
<!-- theme UI controls like checkboxes and text fields -->
|
||||
<item name="colorAccent">#FF4081</item>
|
||||
<item name="colorAccent">#FF5722</item>
|
||||
<item name="colorSecondary">#FF5722</item>
|
||||
</style>
|
||||
|
||||
<style name="AppTheme.AppBarOverlay" parent="ThemeOverlay.MaterialComponents.Dark.ActionBar" />
|
||||
|
||||
<style name="AppTheme.PopupOverlay" parent="ThemeOverlay.MaterialComponents.Light" />
|
||||
|
||||
</resources>
|
||||
|
7
android/app/src/main/res/xml/filepaths.xml
Normal file
7
android/app/src/main/res/xml/filepaths.xml
Normal file
@@ -0,0 +1,7 @@
|
||||
<paths>
|
||||
<files-path path="/" name="files" />
|
||||
<cache-path path="/" name="cache" />
|
||||
<external-path path="/" name="external" />
|
||||
<external-files-path path="/" name="external-files" />
|
||||
<external-cache-path path="/" name="external-cache" />
|
||||
</paths>
|
@@ -1,3 +1,3 @@
|
||||
#Sun Nov 18 03:24:23 CET 2018
|
||||
VERSION_NAME=0.0.13
|
||||
VERSION_CODE=13
|
||||
#Thu Mar 05 15:29:10 UTC 2020
|
||||
VERSION_NAME=1.8.0
|
||||
VERSION_CODE=23
|
||||
|
@@ -7,8 +7,8 @@ buildscript {
|
||||
jcenter()
|
||||
}
|
||||
dependencies {
|
||||
classpath 'com.android.tools.build:gradle:3.2.1'
|
||||
classpath 'com.google.gms:google-services:4.2.0'
|
||||
classpath 'com.android.tools.build:gradle:4.1.0'
|
||||
classpath 'com.google.gms:google-services:4.3.4'
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -1,6 +1,6 @@
|
||||
#Wed Sep 26 22:10:14 CEST 2018
|
||||
#Tue Nov 03 14:10:19 CET 2020
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-4.6-all.zip
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-6.5-all.zip
|
||||
|
58
androidExportReader/.gitignore
vendored
Normal file
58
androidExportReader/.gitignore
vendored
Normal file
@@ -0,0 +1,58 @@
|
||||
# Created by https://www.toptal.com/developers/gitignore/api/java,gradle
|
||||
# Edit at https://www.toptal.com/developers/gitignore?templates=java,gradle
|
||||
|
||||
### Java ###
|
||||
# Compiled class file
|
||||
*.class
|
||||
|
||||
# Log file
|
||||
*.log
|
||||
|
||||
# BlueJ files
|
||||
*.ctxt
|
||||
|
||||
# Mobile Tools for Java (J2ME)
|
||||
.mtj.tmp/
|
||||
|
||||
# Package Files #
|
||||
*.jar
|
||||
*.war
|
||||
*.nar
|
||||
*.ear
|
||||
*.zip
|
||||
*.tar.gz
|
||||
*.rar
|
||||
|
||||
# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
|
||||
hs_err_pid*
|
||||
replay_pid*
|
||||
|
||||
### Gradle ###
|
||||
.gradle
|
||||
**/build/
|
||||
!src/**/build/
|
||||
|
||||
# Ignore Gradle GUI config
|
||||
gradle-app.setting
|
||||
|
||||
# Avoid ignoring Gradle wrapper jar file (.jar files are usually ignored)
|
||||
!gradle-wrapper.jar
|
||||
|
||||
# Avoid ignore Gradle wrappper properties
|
||||
!gradle-wrapper.properties
|
||||
|
||||
# Cache of project
|
||||
.gradletasknamecache
|
||||
|
||||
# Eclipse Gradle plugin generated files
|
||||
# Eclipse Core
|
||||
.project
|
||||
# JDT-specific (Eclipse Java Development Tools)
|
||||
.classpath
|
||||
|
||||
### Gradle Patch ###
|
||||
# Java heap dump
|
||||
*.hprof
|
||||
|
||||
# End of https://www.toptal.com/developers/gitignore/api/java,gradle
|
||||
|
8
androidExportReader/.idea/.gitignore
generated
vendored
Normal file
8
androidExportReader/.idea/.gitignore
generated
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
# Default ignored files
|
||||
/shelf/
|
||||
/workspace.xml
|
||||
# Editor-based HTTP Client requests
|
||||
/httpRequests/
|
||||
# Datasource local storage ignored files
|
||||
/dataSources/
|
||||
/dataSources.local.xml
|
6
androidExportReader/.idea/compiler.xml
generated
Normal file
6
androidExportReader/.idea/compiler.xml
generated
Normal file
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="CompilerConfiguration">
|
||||
<bytecodeTargetLevel target="18" />
|
||||
</component>
|
||||
</project>
|
17
androidExportReader/.idea/gradle.xml
generated
Normal file
17
androidExportReader/.idea/gradle.xml
generated
Normal file
@@ -0,0 +1,17 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="GradleMigrationSettings" migrationVersion="1" />
|
||||
<component name="GradleSettings">
|
||||
<option name="linkedExternalProjectsSettings">
|
||||
<GradleProjectSettings>
|
||||
<option name="distributionType" value="DEFAULT_WRAPPED" />
|
||||
<option name="externalProjectPath" value="$PROJECT_DIR$" />
|
||||
<option name="modules">
|
||||
<set>
|
||||
<option value="$PROJECT_DIR$" />
|
||||
</set>
|
||||
</option>
|
||||
</GradleProjectSettings>
|
||||
</option>
|
||||
</component>
|
||||
</project>
|
11
androidExportReader/.idea/inspectionProfiles/Project_Default.xml
generated
Normal file
11
androidExportReader/.idea/inspectionProfiles/Project_Default.xml
generated
Normal file
@@ -0,0 +1,11 @@
|
||||
<component name="InspectionProjectProfileManager">
|
||||
<profile version="1.0">
|
||||
<option name="myName" value="Project Default" />
|
||||
<inspection_tool class="JavadocReference" enabled="true" level="WARNING" enabled_by_default="true" editorAttributes="WARNING_ATTRIBUTES" />
|
||||
<inspection_tool class="SpellCheckingInspection" enabled="false" level="TYPO" enabled_by_default="false">
|
||||
<option name="processCode" value="true" />
|
||||
<option name="processLiterals" value="true" />
|
||||
<option name="processComments" value="true" />
|
||||
</inspection_tool>
|
||||
</profile>
|
||||
</component>
|
25
androidExportReader/.idea/jarRepositories.xml
generated
Normal file
25
androidExportReader/.idea/jarRepositories.xml
generated
Normal file
@@ -0,0 +1,25 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="RemoteRepositoriesConfiguration">
|
||||
<remote-repository>
|
||||
<option name="id" value="central" />
|
||||
<option name="name" value="Maven Central repository" />
|
||||
<option name="url" value="https://repo1.maven.org/maven2" />
|
||||
</remote-repository>
|
||||
<remote-repository>
|
||||
<option name="id" value="jboss.community" />
|
||||
<option name="name" value="JBoss Community repository" />
|
||||
<option name="url" value="https://repository.jboss.org/nexus/content/repositories/public/" />
|
||||
</remote-repository>
|
||||
<remote-repository>
|
||||
<option name="id" value="MavenRepo" />
|
||||
<option name="name" value="MavenRepo" />
|
||||
<option name="url" value="https://repo.maven.apache.org/maven2/" />
|
||||
</remote-repository>
|
||||
<remote-repository>
|
||||
<option name="id" value="maven" />
|
||||
<option name="name" value="maven" />
|
||||
<option name="url" value="https://jitpack.io" />
|
||||
</remote-repository>
|
||||
</component>
|
||||
</project>
|
10
androidExportReader/.idea/misc.xml
generated
Normal file
10
androidExportReader/.idea/misc.xml
generated
Normal file
@@ -0,0 +1,10 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ExternalStorageConfigurationManager" enabled="true" />
|
||||
<component name="FrameworkDetectionExcludesConfiguration">
|
||||
<file type="web" url="file://$PROJECT_DIR$" />
|
||||
</component>
|
||||
<component name="ProjectRootManager" version="2" languageLevel="JDK_18" default="true" project-jdk-name="openjdk-18" project-jdk-type="JavaSDK">
|
||||
<output url="file://$PROJECT_DIR$/out" />
|
||||
</component>
|
||||
</project>
|
6
androidExportReader/.idea/vcs.xml
generated
Normal file
6
androidExportReader/.idea/vcs.xml
generated
Normal file
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="VcsDirectoryMappings">
|
||||
<mapping directory="$PROJECT_DIR$/.." vcs="Git" />
|
||||
</component>
|
||||
</project>
|
47
androidExportReader/build.gradle
Normal file
47
androidExportReader/build.gradle
Normal file
@@ -0,0 +1,47 @@
|
||||
|
||||
buildscript {
|
||||
repositories {
|
||||
gradlePluginPortal()
|
||||
}
|
||||
dependencies {
|
||||
classpath 'gradle.plugin.com.github.johnrengelman:shadow:7.1.2'
|
||||
}
|
||||
}
|
||||
|
||||
plugins {
|
||||
id 'java'
|
||||
id("com.github.johnrengelman.shadow") version "7.1.2"
|
||||
id 'application'
|
||||
}
|
||||
|
||||
group 'com.blackforestbytes'
|
||||
version '1.0-SNAPSHOT'
|
||||
|
||||
repositories {
|
||||
mavenCentral()
|
||||
maven { url "https://jitpack.io" }
|
||||
}
|
||||
|
||||
application {
|
||||
mainClass = 'com.blackforestbytes.Main'
|
||||
}
|
||||
|
||||
jar {
|
||||
manifest {
|
||||
attributes 'Main-Class': application.mainClass
|
||||
}
|
||||
}
|
||||
|
||||
tasks.jar {
|
||||
manifest.attributes["Main-Class"] = application.mainClass
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation 'com.github.RalleYTN:SimpleJSON:2.1.1'
|
||||
testImplementation 'org.junit.jupiter:junit-jupiter-api:5.8.1'
|
||||
testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.8.1'
|
||||
}
|
||||
|
||||
test {
|
||||
useJUnitPlatform()
|
||||
}
|
BIN
androidExportReader/gradle/wrapper/gradle-wrapper.jar
vendored
Normal file
BIN
androidExportReader/gradle/wrapper/gradle-wrapper.jar
vendored
Normal file
Binary file not shown.
5
androidExportReader/gradle/wrapper/gradle-wrapper.properties
vendored
Normal file
5
androidExportReader/gradle/wrapper/gradle-wrapper.properties
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-7.5.1-bin.zip
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
240
androidExportReader/gradlew
vendored
Executable file
240
androidExportReader/gradlew
vendored
Executable file
@@ -0,0 +1,240 @@
|
||||
#!/bin/sh
|
||||
|
||||
#
|
||||
# Copyright © 2015-2021 the original authors.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# https://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#
|
||||
|
||||
##############################################################################
|
||||
#
|
||||
# Gradle start up script for POSIX generated by Gradle.
|
||||
#
|
||||
# Important for running:
|
||||
#
|
||||
# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is
|
||||
# noncompliant, but you have some other compliant shell such as ksh or
|
||||
# bash, then to run this script, type that shell name before the whole
|
||||
# command line, like:
|
||||
#
|
||||
# ksh Gradle
|
||||
#
|
||||
# Busybox and similar reduced shells will NOT work, because this script
|
||||
# requires all of these POSIX shell features:
|
||||
# * functions;
|
||||
# * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,
|
||||
# «${var#prefix}», «${var%suffix}», and «$( cmd )»;
|
||||
# * compound commands having a testable exit status, especially «case»;
|
||||
# * various built-in commands including «command», «set», and «ulimit».
|
||||
#
|
||||
# Important for patching:
|
||||
#
|
||||
# (2) This script targets any POSIX shell, so it avoids extensions provided
|
||||
# by Bash, Ksh, etc; in particular arrays are avoided.
|
||||
#
|
||||
# The "traditional" practice of packing multiple parameters into a
|
||||
# space-separated string is a well documented source of bugs and security
|
||||
# problems, so this is (mostly) avoided, by progressively accumulating
|
||||
# options in "$@", and eventually passing that to Java.
|
||||
#
|
||||
# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,
|
||||
# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;
|
||||
# see the in-line comments for details.
|
||||
#
|
||||
# There are tweaks for specific operating systems such as AIX, CygWin,
|
||||
# Darwin, MinGW, and NonStop.
|
||||
#
|
||||
# (3) This script is generated from the Groovy template
|
||||
# https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
|
||||
# within the Gradle project.
|
||||
#
|
||||
# You can find Gradle at https://github.com/gradle/gradle/.
|
||||
#
|
||||
##############################################################################
|
||||
|
||||
# Attempt to set APP_HOME
|
||||
|
||||
# Resolve links: $0 may be a link
|
||||
app_path=$0
|
||||
|
||||
# Need this for daisy-chained symlinks.
|
||||
while
|
||||
APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path
|
||||
[ -h "$app_path" ]
|
||||
do
|
||||
ls=$( ls -ld "$app_path" )
|
||||
link=${ls#*' -> '}
|
||||
case $link in #(
|
||||
/*) app_path=$link ;; #(
|
||||
*) app_path=$APP_HOME$link ;;
|
||||
esac
|
||||
done
|
||||
|
||||
APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit
|
||||
|
||||
APP_NAME="Gradle"
|
||||
APP_BASE_NAME=${0##*/}
|
||||
|
||||
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
|
||||
|
||||
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
||||
MAX_FD=maximum
|
||||
|
||||
warn () {
|
||||
echo "$*"
|
||||
} >&2
|
||||
|
||||
die () {
|
||||
echo
|
||||
echo "$*"
|
||||
echo
|
||||
exit 1
|
||||
} >&2
|
||||
|
||||
# OS specific support (must be 'true' or 'false').
|
||||
cygwin=false
|
||||
msys=false
|
||||
darwin=false
|
||||
nonstop=false
|
||||
case "$( uname )" in #(
|
||||
CYGWIN* ) cygwin=true ;; #(
|
||||
Darwin* ) darwin=true ;; #(
|
||||
MSYS* | MINGW* ) msys=true ;; #(
|
||||
NONSTOP* ) nonstop=true ;;
|
||||
esac
|
||||
|
||||
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
|
||||
|
||||
|
||||
# Determine the Java command to use to start the JVM.
|
||||
if [ -n "$JAVA_HOME" ] ; then
|
||||
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
|
||||
# IBM's JDK on AIX uses strange locations for the executables
|
||||
JAVACMD=$JAVA_HOME/jre/sh/java
|
||||
else
|
||||
JAVACMD=$JAVA_HOME/bin/java
|
||||
fi
|
||||
if [ ! -x "$JAVACMD" ] ; then
|
||||
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
|
||||
|
||||
Please set the JAVA_HOME variable in your environment to match the
|
||||
location of your Java installation."
|
||||
fi
|
||||
else
|
||||
JAVACMD=java
|
||||
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||
|
||||
Please set the JAVA_HOME variable in your environment to match the
|
||||
location of your Java installation."
|
||||
fi
|
||||
|
||||
# Increase the maximum file descriptors if we can.
|
||||
if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
|
||||
case $MAX_FD in #(
|
||||
max*)
|
||||
MAX_FD=$( ulimit -H -n ) ||
|
||||
warn "Could not query maximum file descriptor limit"
|
||||
esac
|
||||
case $MAX_FD in #(
|
||||
'' | soft) :;; #(
|
||||
*)
|
||||
ulimit -n "$MAX_FD" ||
|
||||
warn "Could not set maximum file descriptor limit to $MAX_FD"
|
||||
esac
|
||||
fi
|
||||
|
||||
# Collect all arguments for the java command, stacking in reverse order:
|
||||
# * args from the command line
|
||||
# * the main class name
|
||||
# * -classpath
|
||||
# * -D...appname settings
|
||||
# * --module-path (only if needed)
|
||||
# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.
|
||||
|
||||
# For Cygwin or MSYS, switch paths to Windows format before running java
|
||||
if "$cygwin" || "$msys" ; then
|
||||
APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
|
||||
CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
|
||||
|
||||
JAVACMD=$( cygpath --unix "$JAVACMD" )
|
||||
|
||||
# Now convert the arguments - kludge to limit ourselves to /bin/sh
|
||||
for arg do
|
||||
if
|
||||
case $arg in #(
|
||||
-*) false ;; # don't mess with options #(
|
||||
/?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath
|
||||
[ -e "$t" ] ;; #(
|
||||
*) false ;;
|
||||
esac
|
||||
then
|
||||
arg=$( cygpath --path --ignore --mixed "$arg" )
|
||||
fi
|
||||
# Roll the args list around exactly as many times as the number of
|
||||
# args, so each arg winds up back in the position where it started, but
|
||||
# possibly modified.
|
||||
#
|
||||
# NB: a `for` loop captures its iteration list before it begins, so
|
||||
# changing the positional parameters here affects neither the number of
|
||||
# iterations, nor the values presented in `arg`.
|
||||
shift # remove old arg
|
||||
set -- "$@" "$arg" # push replacement arg
|
||||
done
|
||||
fi
|
||||
|
||||
# Collect all arguments for the java command;
|
||||
# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of
|
||||
# shell script including quotes and variable substitutions, so put them in
|
||||
# double quotes to make sure that they get re-expanded; and
|
||||
# * put everything else in single quotes, so that it's not re-expanded.
|
||||
|
||||
set -- \
|
||||
"-Dorg.gradle.appname=$APP_BASE_NAME" \
|
||||
-classpath "$CLASSPATH" \
|
||||
org.gradle.wrapper.GradleWrapperMain \
|
||||
"$@"
|
||||
|
||||
# Stop when "xargs" is not available.
|
||||
if ! command -v xargs >/dev/null 2>&1
|
||||
then
|
||||
die "xargs is not available"
|
||||
fi
|
||||
|
||||
# Use "xargs" to parse quoted args.
|
||||
#
|
||||
# With -n1 it outputs one arg per line, with the quotes and backslashes removed.
|
||||
#
|
||||
# In Bash we could simply go:
|
||||
#
|
||||
# readarray ARGS < <( xargs -n1 <<<"$var" ) &&
|
||||
# set -- "${ARGS[@]}" "$@"
|
||||
#
|
||||
# but POSIX shell has neither arrays nor command substitution, so instead we
|
||||
# post-process each arg (as a line of input to sed) to backslash-escape any
|
||||
# character that might be a shell metacharacter, then use eval to reverse
|
||||
# that process (while maintaining the separation between arguments), and wrap
|
||||
# the whole thing up as a single "set" statement.
|
||||
#
|
||||
# This will of course break if any of these variables contains a newline or
|
||||
# an unmatched quote.
|
||||
#
|
||||
|
||||
eval "set -- $(
|
||||
printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" |
|
||||
xargs -n1 |
|
||||
sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' |
|
||||
tr '\n' ' '
|
||||
)" '"$@"'
|
||||
|
||||
exec "$JAVACMD" "$@"
|
91
androidExportReader/gradlew.bat
vendored
Normal file
91
androidExportReader/gradlew.bat
vendored
Normal file
@@ -0,0 +1,91 @@
|
||||
@rem
|
||||
@rem Copyright 2015 the original author or authors.
|
||||
@rem
|
||||
@rem Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@rem you may not use this file except in compliance with the License.
|
||||
@rem You may obtain a copy of the License at
|
||||
@rem
|
||||
@rem https://www.apache.org/licenses/LICENSE-2.0
|
||||
@rem
|
||||
@rem Unless required by applicable law or agreed to in writing, software
|
||||
@rem distributed under the License is distributed on an "AS IS" BASIS,
|
||||
@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
@rem See the License for the specific language governing permissions and
|
||||
@rem limitations under the License.
|
||||
@rem
|
||||
|
||||
@if "%DEBUG%"=="" @echo off
|
||||
@rem ##########################################################################
|
||||
@rem
|
||||
@rem Gradle startup script for Windows
|
||||
@rem
|
||||
@rem ##########################################################################
|
||||
|
||||
@rem Set local scope for the variables with windows NT shell
|
||||
if "%OS%"=="Windows_NT" setlocal
|
||||
|
||||
set DIRNAME=%~dp0
|
||||
if "%DIRNAME%"=="" set DIRNAME=.
|
||||
set APP_BASE_NAME=%~n0
|
||||
set APP_HOME=%DIRNAME%
|
||||
|
||||
@rem Resolve any "." and ".." in APP_HOME to make it shorter.
|
||||
for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
|
||||
|
||||
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||
set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
|
||||
|
||||
@rem Find java.exe
|
||||
if defined JAVA_HOME goto findJavaFromJavaHome
|
||||
|
||||
set JAVA_EXE=java.exe
|
||||
%JAVA_EXE% -version >NUL 2>&1
|
||||
if %ERRORLEVEL% equ 0 goto execute
|
||||
|
||||
echo.
|
||||
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||
echo.
|
||||
echo Please set the JAVA_HOME variable in your environment to match the
|
||||
echo location of your Java installation.
|
||||
|
||||
goto fail
|
||||
|
||||
:findJavaFromJavaHome
|
||||
set JAVA_HOME=%JAVA_HOME:"=%
|
||||
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
|
||||
|
||||
if exist "%JAVA_EXE%" goto execute
|
||||
|
||||
echo.
|
||||
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
|
||||
echo.
|
||||
echo Please set the JAVA_HOME variable in your environment to match the
|
||||
echo location of your Java installation.
|
||||
|
||||
goto fail
|
||||
|
||||
:execute
|
||||
@rem Setup the command line
|
||||
|
||||
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
|
||||
|
||||
|
||||
@rem Execute Gradle
|
||||
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
|
||||
|
||||
:end
|
||||
@rem End local scope for the variables with windows NT shell
|
||||
if %ERRORLEVEL% equ 0 goto mainEnd
|
||||
|
||||
:fail
|
||||
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
|
||||
rem the _cmd.exe /c_ return code!
|
||||
set EXIT_CODE=%ERRORLEVEL%
|
||||
if %EXIT_CODE% equ 0 set EXIT_CODE=1
|
||||
if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE%
|
||||
exit /b %EXIT_CODE%
|
||||
|
||||
:mainEnd
|
||||
if "%OS%"=="Windows_NT" endlocal
|
||||
|
||||
:omega
|
2
androidExportReader/settings.gradle
Normal file
2
androidExportReader/settings.gradle
Normal file
@@ -0,0 +1,2 @@
|
||||
rootProject.name = 'androidExportReader'
|
||||
|
104
androidExportReader/src/main/java/com/blackforestbytes/Main.java
Normal file
104
androidExportReader/src/main/java/com/blackforestbytes/Main.java
Normal file
@@ -0,0 +1,104 @@
|
||||
package com.blackforestbytes;
|
||||
|
||||
import de.ralleytn.simple.json.JSONArray;
|
||||
import de.ralleytn.simple.json.JSONFormatter;
|
||||
import de.ralleytn.simple.json.JSONObject;
|
||||
|
||||
import java.io.ObjectInputStream;
|
||||
import java.net.URI;
|
||||
import java.nio.file.FileSystems;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class Main {
|
||||
@SuppressWarnings("unchecked")
|
||||
public static void main(String[] args) {
|
||||
if (args.length != 1) {
|
||||
System.err.println("call with ./androidExportConvert scn_export.dat");
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
|
||||
var path = FileSystems.getDefault().getPath(args[0]).normalize().toAbsolutePath().toUri().toURL();
|
||||
|
||||
ObjectInputStream stream = new ObjectInputStream(path.openStream());
|
||||
|
||||
Map<String, ?> d1 = new HashMap<>((Map<String, ?>)stream.readObject());
|
||||
Map<String, ?> d2 = new HashMap<>((Map<String, ?>)stream.readObject());
|
||||
Map<String, ?> d3 = new HashMap<>((Map<String, ?>)stream.readObject());
|
||||
Map<String, ?> d4 = new HashMap<>((Map<String, ?>)stream.readObject());
|
||||
|
||||
stream.close();
|
||||
|
||||
JSONObject root = new JSONObject();
|
||||
|
||||
var subConfig = new JSONObject();
|
||||
var subIAB = new JSONArray();
|
||||
var subCMessageList = new JSONArray();
|
||||
var subAcks = new JSONArray();
|
||||
var subQueryLog = new JSONArray();
|
||||
|
||||
for (Map.Entry<String, ?> entry : d1.entrySet())
|
||||
{
|
||||
if (entry.getValue() instanceof String) subConfig.put(entry.getKey(), (String)entry.getValue());
|
||||
if (entry.getValue() instanceof Boolean) subConfig.put(entry.getKey(), (Boolean)entry.getValue());
|
||||
if (entry.getValue() instanceof Float) subConfig.put(entry.getKey(), (Float)entry.getValue());
|
||||
if (entry.getValue() instanceof Integer) subConfig.put(entry.getKey(), (Integer)entry.getValue());
|
||||
if (entry.getValue() instanceof Long) subConfig.put(entry.getKey(), (Long)entry.getValue());
|
||||
if (entry.getValue() instanceof Set<?>) subConfig.put(entry.getKey(), ((Set<String>)entry.getValue()).toArray());
|
||||
}
|
||||
|
||||
for (int i = 0; i < (Integer)d2.get("c"); i++) {
|
||||
var obj = new JSONObject();
|
||||
obj.put("key", d2.get("["+i+"]->key"));
|
||||
obj.put("value", d2.get("["+i+"]->value"));
|
||||
subIAB.add(obj);
|
||||
}
|
||||
|
||||
for (int i = 0; i < (Integer)d3.get("message_count"); i++) {
|
||||
if (d3.get("message["+i+"].scnid") == null)
|
||||
throw new Exception("ONF");
|
||||
|
||||
var obj = new JSONObject();
|
||||
obj.put("timestamp", d3.get("message["+i+"].timestamp"));
|
||||
obj.put("title", d3.get("message["+i+"].title"));
|
||||
obj.put("content", d3.get("message["+i+"].content"));
|
||||
obj.put("priority", d3.get("message["+i+"].priority"));
|
||||
obj.put("scnid", d3.get("message["+i+"].scnid"));
|
||||
subCMessageList.add(obj);
|
||||
}
|
||||
|
||||
subAcks.addAll(((Set<String>)d3.get("acks")).stream().map(p -> Long.decode("0x"+p)).toList());
|
||||
|
||||
for (int i = 0; i < (Integer)d4.get("history_count"); i++) {
|
||||
if (d4.get("message["+(i+1000)+"].Name") == null)
|
||||
throw new Exception("ONF");
|
||||
|
||||
var obj = new JSONObject();
|
||||
obj.put("Level", d4.get("message["+(i+1000)+"].Level"));
|
||||
obj.put("Timestamp", d4.get("message["+(i+1000)+"].Timestamp"));
|
||||
obj.put("Name", d4.get("message["+(i+1000)+"].Name"));
|
||||
obj.put("URL", d4.get("message["+(i+1000)+"].URL"));
|
||||
obj.put("Response", d4.get("message["+(i+1000)+"].Response"));
|
||||
obj.put("ResponseCode", d4.get("message["+(i+1000)+"].ResponseCode"));
|
||||
obj.put("ExceptionString", d4.get("message["+(i+1000)+"].ExceptionString"));
|
||||
subQueryLog.add(obj);
|
||||
}
|
||||
|
||||
root.put("config", subConfig);
|
||||
root.put("iab", subIAB);
|
||||
root.put("cmessagelist", subCMessageList);
|
||||
root.put("acks", subAcks);
|
||||
root.put("querylog", subQueryLog);
|
||||
|
||||
System.out.println(new JSONFormatter().format(root.toString()));
|
||||
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
15
android_v2/.gitignore
vendored
Normal file
15
android_v2/.gitignore
vendored
Normal file
@@ -0,0 +1,15 @@
|
||||
*.iml
|
||||
.gradle
|
||||
/local.properties
|
||||
/.idea/caches
|
||||
/.idea/libraries
|
||||
/.idea/modules.xml
|
||||
/.idea/workspace.xml
|
||||
/.idea/navEditor.xml
|
||||
/.idea/assetWizardSettings.xml
|
||||
.DS_Store
|
||||
/build
|
||||
/captures
|
||||
.externalNativeBuild
|
||||
.cxx
|
||||
local.properties
|
3
android_v2/.idea/.gitignore
generated
vendored
Normal file
3
android_v2/.idea/.gitignore
generated
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
# Default ignored files
|
||||
/shelf/
|
||||
/workspace.xml
|
1
android_v2/.idea/.name
generated
Normal file
1
android_v2/.idea/.name
generated
Normal file
@@ -0,0 +1 @@
|
||||
Simplecloudnotifier2
|
119
android_v2/.idea/codeStyles
generated
Normal file
119
android_v2/.idea/codeStyles
generated
Normal file
@@ -0,0 +1,119 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ProjectCodeStyleConfiguration">
|
||||
<code_scheme name="Project" version="173">
|
||||
<codeStyleSettings language="XML">
|
||||
<indentOptions>
|
||||
<option name="CONTINUATION_INDENT_SIZE" value="4" />
|
||||
</indentOptions>
|
||||
<arrangement>
|
||||
<rules>
|
||||
<section>
|
||||
<rule>
|
||||
<match>
|
||||
<AND>
|
||||
<NAME>xmlns:android</NAME>
|
||||
<XML_ATTRIBUTE />
|
||||
<XML_NAMESPACE>^$</XML_NAMESPACE>
|
||||
</AND>
|
||||
</match>
|
||||
</rule>
|
||||
</section>
|
||||
<section>
|
||||
<rule>
|
||||
<match>
|
||||
<AND>
|
||||
<NAME>xmlns:.*</NAME>
|
||||
<XML_ATTRIBUTE />
|
||||
<XML_NAMESPACE>^$</XML_NAMESPACE>
|
||||
</AND>
|
||||
</match>
|
||||
<order>BY_NAME</order>
|
||||
</rule>
|
||||
</section>
|
||||
<section>
|
||||
<rule>
|
||||
<match>
|
||||
<AND>
|
||||
<NAME>.*:id</NAME>
|
||||
<XML_ATTRIBUTE />
|
||||
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
|
||||
</AND>
|
||||
</match>
|
||||
</rule>
|
||||
</section>
|
||||
<section>
|
||||
<rule>
|
||||
<match>
|
||||
<AND>
|
||||
<NAME>.*:name</NAME>
|
||||
<XML_ATTRIBUTE />
|
||||
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
|
||||
</AND>
|
||||
</match>
|
||||
</rule>
|
||||
</section>
|
||||
<section>
|
||||
<rule>
|
||||
<match>
|
||||
<AND>
|
||||
<NAME>name</NAME>
|
||||
<XML_ATTRIBUTE />
|
||||
<XML_NAMESPACE>^$</XML_NAMESPACE>
|
||||
</AND>
|
||||
</match>
|
||||
</rule>
|
||||
</section>
|
||||
<section>
|
||||
<rule>
|
||||
<match>
|
||||
<AND>
|
||||
<NAME>style</NAME>
|
||||
<XML_ATTRIBUTE />
|
||||
<XML_NAMESPACE>^$</XML_NAMESPACE>
|
||||
</AND>
|
||||
</match>
|
||||
</rule>
|
||||
</section>
|
||||
<section>
|
||||
<rule>
|
||||
<match>
|
||||
<AND>
|
||||
<NAME>.*</NAME>
|
||||
<XML_ATTRIBUTE />
|
||||
<XML_NAMESPACE>^$</XML_NAMESPACE>
|
||||
</AND>
|
||||
</match>
|
||||
<order>BY_NAME</order>
|
||||
</rule>
|
||||
</section>
|
||||
<section>
|
||||
<rule>
|
||||
<match>
|
||||
<AND>
|
||||
<NAME>.*</NAME>
|
||||
<XML_ATTRIBUTE />
|
||||
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
|
||||
</AND>
|
||||
</match>
|
||||
<order>ANDROID_ATTRIBUTE_ORDER</order>
|
||||
</rule>
|
||||
</section>
|
||||
<section>
|
||||
<rule>
|
||||
<match>
|
||||
<AND>
|
||||
<NAME>.*</NAME>
|
||||
<XML_ATTRIBUTE />
|
||||
<XML_NAMESPACE>.*</XML_NAMESPACE>
|
||||
</AND>
|
||||
</match>
|
||||
<order>BY_NAME</order>
|
||||
</rule>
|
||||
</section>
|
||||
</rules>
|
||||
</arrangement>
|
||||
</codeStyleSettings>
|
||||
</code_scheme>
|
||||
</component>
|
||||
</project>
|
6
android_v2/.idea/compiler.xml
generated
Normal file
6
android_v2/.idea/compiler.xml
generated
Normal file
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="CompilerConfiguration">
|
||||
<bytecodeTargetLevel target="17" />
|
||||
</component>
|
||||
</project>
|
19
android_v2/.idea/gradle.xml
generated
Normal file
19
android_v2/.idea/gradle.xml
generated
Normal file
@@ -0,0 +1,19 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="GradleSettings">
|
||||
<option name="linkedExternalProjectsSettings">
|
||||
<GradleProjectSettings>
|
||||
<option name="testRunner" value="GRADLE" />
|
||||
<option name="distributionType" value="DEFAULT_WRAPPED" />
|
||||
<option name="externalProjectPath" value="$PROJECT_DIR$" />
|
||||
<option name="gradleJvm" value="jbr-17" />
|
||||
<option name="modules">
|
||||
<set>
|
||||
<option value="$PROJECT_DIR$" />
|
||||
<option value="$PROJECT_DIR$/app" />
|
||||
</set>
|
||||
</option>
|
||||
</GradleProjectSettings>
|
||||
</option>
|
||||
</component>
|
||||
</project>
|
46
android_v2/.idea/inspectionProfiles/Project_Default.xml
generated
Normal file
46
android_v2/.idea/inspectionProfiles/Project_Default.xml
generated
Normal file
@@ -0,0 +1,46 @@
|
||||
<component name="InspectionProjectProfileManager">
|
||||
<profile version="1.0">
|
||||
<option name="myName" value="Project Default" />
|
||||
<inspection_tool class="PreviewAnnotationInFunctionWithParameters" enabled="true" level="ERROR" enabled_by_default="true">
|
||||
<option name="composableFile" value="true" />
|
||||
<option name="previewFile" value="true" />
|
||||
</inspection_tool>
|
||||
<inspection_tool class="PreviewApiLevelMustBeValid" enabled="true" level="ERROR" enabled_by_default="true">
|
||||
<option name="composableFile" value="true" />
|
||||
<option name="previewFile" value="true" />
|
||||
</inspection_tool>
|
||||
<inspection_tool class="PreviewDimensionRespectsLimit" enabled="true" level="WARNING" enabled_by_default="true">
|
||||
<option name="composableFile" value="true" />
|
||||
<option name="previewFile" value="true" />
|
||||
</inspection_tool>
|
||||
<inspection_tool class="PreviewFontScaleMustBeGreaterThanZero" enabled="true" level="ERROR" enabled_by_default="true">
|
||||
<option name="composableFile" value="true" />
|
||||
<option name="previewFile" value="true" />
|
||||
</inspection_tool>
|
||||
<inspection_tool class="PreviewMultipleParameterProviders" enabled="true" level="ERROR" enabled_by_default="true">
|
||||
<option name="composableFile" value="true" />
|
||||
<option name="previewFile" value="true" />
|
||||
</inspection_tool>
|
||||
<inspection_tool class="PreviewMustBeTopLevelFunction" enabled="true" level="ERROR" enabled_by_default="true">
|
||||
<option name="composableFile" value="true" />
|
||||
<option name="previewFile" value="true" />
|
||||
</inspection_tool>
|
||||
<inspection_tool class="PreviewNeedsComposableAnnotation" enabled="true" level="ERROR" enabled_by_default="true">
|
||||
<option name="composableFile" value="true" />
|
||||
<option name="previewFile" value="true" />
|
||||
</inspection_tool>
|
||||
<inspection_tool class="PreviewNotSupportedInUnitTestFiles" enabled="true" level="ERROR" enabled_by_default="true">
|
||||
<option name="composableFile" value="true" />
|
||||
<option name="previewFile" value="true" />
|
||||
</inspection_tool>
|
||||
<inspection_tool class="PreviewPickerAnnotation" enabled="true" level="ERROR" enabled_by_default="true">
|
||||
<option name="composableFile" value="true" />
|
||||
<option name="previewFile" value="true" />
|
||||
</inspection_tool>
|
||||
<inspection_tool class="SpellCheckingInspection" enabled="false" level="TYPO" enabled_by_default="false">
|
||||
<option name="processCode" value="true" />
|
||||
<option name="processLiterals" value="true" />
|
||||
<option name="processComments" value="true" />
|
||||
</inspection_tool>
|
||||
</profile>
|
||||
</component>
|
6
android_v2/.idea/kotlinc.xml
generated
Normal file
6
android_v2/.idea/kotlinc.xml
generated
Normal file
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="KotlinJpsPluginSettings">
|
||||
<option name="version" value="1.8.10" />
|
||||
</component>
|
||||
</project>
|
10
android_v2/.idea/misc.xml
generated
Normal file
10
android_v2/.idea/misc.xml
generated
Normal file
@@ -0,0 +1,10 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ExternalStorageConfigurationManager" enabled="true" />
|
||||
<component name="ProjectRootManager" version="2" languageLevel="JDK_17" default="true" project-jdk-name="jbr-17" project-jdk-type="JavaSDK">
|
||||
<output url="file://$PROJECT_DIR$/build/classes" />
|
||||
</component>
|
||||
<component name="ProjectType">
|
||||
<option name="id" value="Android" />
|
||||
</component>
|
||||
</project>
|
6
android_v2/.idea/vcs.xml
generated
Normal file
6
android_v2/.idea/vcs.xml
generated
Normal file
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="VcsDirectoryMappings">
|
||||
<mapping directory="$PROJECT_DIR$/.." vcs="Git" />
|
||||
</component>
|
||||
</project>
|
1
android_v2/app/.gitignore
vendored
Normal file
1
android_v2/app/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
||||
/build
|
66
android_v2/app/build.gradle.kts
Normal file
66
android_v2/app/build.gradle.kts
Normal file
@@ -0,0 +1,66 @@
|
||||
plugins {
|
||||
id("com.android.application")
|
||||
id("org.jetbrains.kotlin.android")
|
||||
}
|
||||
|
||||
android {
|
||||
namespace = "com.blackforestbytes.simplecloudnotifier2"
|
||||
compileSdk = 33
|
||||
|
||||
defaultConfig {
|
||||
applicationId = "com.blackforestbytes.simplecloudnotifier2"
|
||||
minSdk = 29
|
||||
targetSdk = 33
|
||||
versionCode = 1
|
||||
versionName = "1.0"
|
||||
|
||||
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
|
||||
vectorDrawables {
|
||||
useSupportLibrary = true
|
||||
}
|
||||
}
|
||||
|
||||
buildTypes {
|
||||
release {
|
||||
isMinifyEnabled = false
|
||||
proguardFiles(getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro")
|
||||
}
|
||||
}
|
||||
compileOptions {
|
||||
sourceCompatibility = JavaVersion.VERSION_1_8
|
||||
targetCompatibility = JavaVersion.VERSION_1_8
|
||||
}
|
||||
kotlinOptions {
|
||||
jvmTarget = "1.8"
|
||||
}
|
||||
buildFeatures {
|
||||
compose = true
|
||||
}
|
||||
composeOptions {
|
||||
kotlinCompilerExtensionVersion = "1.4.3"
|
||||
}
|
||||
packaging {
|
||||
resources {
|
||||
excludes += "/META-INF/{AL2.0,LGPL2.1}"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
|
||||
implementation("androidx.core:core-ktx:1.9.0")
|
||||
implementation("androidx.lifecycle:lifecycle-runtime-ktx:2.6.1")
|
||||
implementation("androidx.activity:activity-compose:1.7.0")
|
||||
implementation(platform("androidx.compose:compose-bom:2023.03.00"))
|
||||
implementation("androidx.compose.ui:ui")
|
||||
implementation("androidx.compose.ui:ui-graphics")
|
||||
implementation("androidx.compose.ui:ui-tooling-preview")
|
||||
implementation("androidx.compose.material3:material3")
|
||||
testImplementation("junit:junit:4.13.2")
|
||||
androidTestImplementation("androidx.test.ext:junit:1.1.5")
|
||||
androidTestImplementation("androidx.test.espresso:espresso-core:3.5.1")
|
||||
androidTestImplementation(platform("androidx.compose:compose-bom:2023.03.00"))
|
||||
androidTestImplementation("androidx.compose.ui:ui-test-junit4")
|
||||
debugImplementation("androidx.compose.ui:ui-tooling")
|
||||
debugImplementation("androidx.compose.ui:ui-test-manifest")
|
||||
}
|
21
android_v2/app/proguard-rules.pro
vendored
Normal file
21
android_v2/app/proguard-rules.pro
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
# Add project specific ProGuard rules here.
|
||||
# You can control the set of applied configuration files using the
|
||||
# proguardFiles setting in build.gradle.
|
||||
#
|
||||
# For more details, see
|
||||
# http://developer.android.com/guide/developing/tools/proguard.html
|
||||
|
||||
# If your project uses WebView with JS, uncomment the following
|
||||
# and specify the fully qualified class name to the JavaScript interface
|
||||
# class:
|
||||
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
|
||||
# public *;
|
||||
#}
|
||||
|
||||
# Uncomment this to preserve the line number information for
|
||||
# debugging stack traces.
|
||||
#-keepattributes SourceFile,LineNumberTable
|
||||
|
||||
# If you keep the line number information, uncomment this to
|
||||
# hide the original source file name.
|
||||
#-renamesourcefileattribute SourceFile
|
@@ -0,0 +1,24 @@
|
||||
package com.blackforestbytes.simplecloudnotifier2
|
||||
|
||||
import androidx.test.platform.app.InstrumentationRegistry
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
|
||||
import org.junit.Assert.*
|
||||
|
||||
/**
|
||||
* Instrumented test, which will execute on an Android device.
|
||||
*
|
||||
* See [testing documentation](http://d.android.com/tools/testing).
|
||||
*/
|
||||
@RunWith(AndroidJUnit4::class)
|
||||
class ExampleInstrumentedTest {
|
||||
@Test
|
||||
fun useAppContext() {
|
||||
// Context of the app under test.
|
||||
val appContext = InstrumentationRegistry.getInstrumentation().targetContext
|
||||
assertEquals("com.blackforestbytes.simplecloudnotifier2", appContext.packageName)
|
||||
}
|
||||
}
|
28
android_v2/app/src/main/AndroidManifest.xml
Normal file
28
android_v2/app/src/main/AndroidManifest.xml
Normal file
@@ -0,0 +1,28 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools">
|
||||
|
||||
<application
|
||||
android:allowBackup="true"
|
||||
android:dataExtractionRules="@xml/data_extraction_rules"
|
||||
android:fullBackupContent="@xml/backup_rules"
|
||||
android:icon="@mipmap/ic_launcher"
|
||||
android:label="@string/app_name"
|
||||
android:roundIcon="@mipmap/ic_launcher_round"
|
||||
android:supportsRtl="true"
|
||||
android:theme="@style/Theme.Simplecloudnotifier2"
|
||||
tools:targetApi="31">
|
||||
<activity
|
||||
android:name=".MainActivity"
|
||||
android:exported="true"
|
||||
android:label="@string/app_name"
|
||||
android:theme="@style/Theme.Simplecloudnotifier2">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
</application>
|
||||
|
||||
</manifest>
|
@@ -0,0 +1,221 @@
|
||||
package com.blackforestbytes.simplecloudnotifier2
|
||||
|
||||
import android.os.Bundle
|
||||
import androidx.activity.ComponentActivity
|
||||
import androidx.activity.compose.setContent
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.layout.offset
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.foundation.rememberScrollState
|
||||
import androidx.compose.foundation.verticalScroll
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.filled.Menu
|
||||
import androidx.compose.material3.CardDefaults
|
||||
import androidx.compose.material3.CenterAlignedTopAppBar
|
||||
import androidx.compose.material3.ElevatedCard
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
import androidx.compose.material3.FabPosition
|
||||
import androidx.compose.material3.FloatingActionButton
|
||||
import androidx.compose.material3.FloatingActionButtonDefaults
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.IconButton
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.NavigationBar
|
||||
import androidx.compose.material3.NavigationBarItem
|
||||
import androidx.compose.material3.Scaffold
|
||||
import androidx.compose.material3.Surface
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.TopAppBar
|
||||
import androidx.compose.material3.TopAppBarDefaults
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.vector.ImageVector
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.text.style.TextOverflow
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import com.blackforestbytes.simplecloudnotifier2.ui.theme.Simplecloudnotifier2Theme
|
||||
|
||||
class MainActivity : ComponentActivity() {
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
setContent {
|
||||
Simplecloudnotifier2Theme {
|
||||
// A surface container using the 'background' color from the theme
|
||||
Surface(modifier = Modifier.fillMaxSize(), color = MaterialTheme.colorScheme.background) {
|
||||
|
||||
Content()
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
fun Content() {
|
||||
Scaffold(
|
||||
|
||||
topBar = {
|
||||
CenterAlignedTopAppBar(
|
||||
colors = TopAppBarDefaults.centerAlignedTopAppBarColors(
|
||||
containerColor = MaterialTheme.colorScheme.primaryContainer,
|
||||
titleContentColor = MaterialTheme.colorScheme.primary,
|
||||
),
|
||||
title = {
|
||||
Text("Messages", maxLines = 1, overflow = TextOverflow.Ellipsis)
|
||||
},
|
||||
navigationIcon = {
|
||||
IconButton(onClick = { /* do something */ }) {
|
||||
Icon(painterResource(R.drawable.fas_gauge), contentDescription = "Menu", modifier = Modifier.size(24.dp))
|
||||
}
|
||||
},
|
||||
|
||||
actions = {
|
||||
IconButton(onClick = { /* do something */ }) {
|
||||
Icon(painterResource(R.drawable.fas_paper_plane_top), contentDescription = "Send message", modifier = Modifier.size(24.dp))
|
||||
}
|
||||
},
|
||||
)
|
||||
},
|
||||
|
||||
bottomBar = { NavBar() },
|
||||
|
||||
floatingActionButton = { NavFAB() },
|
||||
|
||||
floatingActionButtonPosition = FabPosition.Center,
|
||||
|
||||
) { innerPadding ->
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.padding(innerPadding)
|
||||
.padding(16.dp)
|
||||
.verticalScroll(rememberScrollState()),
|
||||
verticalArrangement = Arrangement.spacedBy(16.dp),
|
||||
) {
|
||||
MessageCard()
|
||||
MessageCard()
|
||||
MessageCard()
|
||||
MessageCard()
|
||||
MessageCard()
|
||||
MessageCard()
|
||||
MessageCard()
|
||||
MessageCard()
|
||||
MessageCard()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun NavBar() {
|
||||
NavigationBar {
|
||||
NavigationBarItem(
|
||||
icon = { Icon(painterResource(R.drawable.fas_road), contentDescription = "Channels", modifier = Modifier.size(32.dp)) },
|
||||
onClick = {},
|
||||
selected = false,
|
||||
)
|
||||
NavigationBarItem(
|
||||
icon = { Icon(painterResource(R.drawable.fas_computer), contentDescription = "Clients", modifier = Modifier.size(32.dp)) },
|
||||
onClick = {},
|
||||
selected = false,
|
||||
)
|
||||
NavigationBarItem(
|
||||
icon = { Icon(painterResource(R.drawable.fas_key), contentDescription = "Keys", modifier = Modifier.size(32.dp)) },
|
||||
onClick = {},
|
||||
selected = false,
|
||||
)
|
||||
NavigationBarItem(
|
||||
icon = { },
|
||||
onClick = {},
|
||||
selected = false,
|
||||
)
|
||||
NavigationBarItem(
|
||||
icon = { Icon(painterResource(R.drawable.fas_bookmark), contentDescription = "Subscriptions", modifier = Modifier.size(32.dp)) },
|
||||
onClick = {},
|
||||
selected = false,
|
||||
)
|
||||
NavigationBarItem(
|
||||
icon = { Icon(painterResource(R.drawable.fas_user), contentDescription = "User", modifier = Modifier.size(32.dp)) },
|
||||
onClick = {},
|
||||
selected = false,
|
||||
)
|
||||
NavigationBarItem(
|
||||
icon = { Icon(painterResource(R.drawable.fas_gear), contentDescription = "Settings", modifier = Modifier.size(32.dp)) },
|
||||
onClick = {},
|
||||
selected = false,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun NavFAB() {
|
||||
Box(){
|
||||
FloatingActionButton(
|
||||
onClick = { /* stub */ },
|
||||
shape = FloatingActionButtonDefaults.shape,
|
||||
modifier = Modifier
|
||||
.align(Alignment.Center)
|
||||
.size(70.dp)
|
||||
.offset(y = 50.dp)
|
||||
) {
|
||||
Icon(
|
||||
painter = painterResource(R.drawable.fas_plus),
|
||||
contentDescription = null,
|
||||
modifier = Modifier.size(45.dp)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun MessageCard() {
|
||||
ElevatedCard(
|
||||
elevation = CardDefaults.cardElevation(
|
||||
defaultElevation = 6.dp
|
||||
),
|
||||
modifier = Modifier.fillMaxWidth().height(height = 100.dp)
|
||||
) {
|
||||
Text(
|
||||
text = "Channel",
|
||||
modifier = Modifier.padding(16.dp),
|
||||
textAlign = TextAlign.Center,
|
||||
)
|
||||
Text(
|
||||
text = "Title",
|
||||
modifier = Modifier.padding(16.dp),
|
||||
textAlign = TextAlign.Center,
|
||||
)
|
||||
Text(
|
||||
text = "Body",
|
||||
modifier = Modifier.padding(16.dp),
|
||||
textAlign = TextAlign.Center,
|
||||
)
|
||||
Text(
|
||||
text = "Date",
|
||||
modifier = Modifier.padding(16.dp),
|
||||
textAlign = TextAlign.Center,
|
||||
)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Preview(showBackground = true)
|
||||
@Composable
|
||||
fun GreetingPreview() {
|
||||
Simplecloudnotifier2Theme {
|
||||
|
||||
Content()
|
||||
|
||||
}
|
||||
}
|
@@ -0,0 +1,11 @@
|
||||
package com.blackforestbytes.simplecloudnotifier2.ui.theme
|
||||
|
||||
import androidx.compose.ui.graphics.Color
|
||||
|
||||
val Purple80 = Color(0xFFD0BCFF)
|
||||
val PurpleGrey80 = Color(0xFFCCC2DC)
|
||||
val Pink80 = Color(0xFFEFB8C8)
|
||||
|
||||
val Purple40 = Color(0xFF6650a4)
|
||||
val PurpleGrey40 = Color(0xFF625b71)
|
||||
val Pink40 = Color(0xFF7D5260)
|
@@ -0,0 +1,70 @@
|
||||
package com.blackforestbytes.simplecloudnotifier2.ui.theme
|
||||
|
||||
import android.app.Activity
|
||||
import android.os.Build
|
||||
import androidx.compose.foundation.isSystemInDarkTheme
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.darkColorScheme
|
||||
import androidx.compose.material3.dynamicDarkColorScheme
|
||||
import androidx.compose.material3.dynamicLightColorScheme
|
||||
import androidx.compose.material3.lightColorScheme
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.SideEffect
|
||||
import androidx.compose.ui.graphics.toArgb
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.platform.LocalView
|
||||
import androidx.core.view.WindowCompat
|
||||
|
||||
private val DarkColorScheme = darkColorScheme(
|
||||
primary = Purple80,
|
||||
secondary = PurpleGrey80,
|
||||
tertiary = Pink80
|
||||
)
|
||||
|
||||
private val LightColorScheme = lightColorScheme(
|
||||
primary = Purple40,
|
||||
secondary = PurpleGrey40,
|
||||
tertiary = Pink40
|
||||
|
||||
/* Other default colors to override
|
||||
background = Color(0xFFFFFBFE),
|
||||
surface = Color(0xFFFFFBFE),
|
||||
onPrimary = Color.White,
|
||||
onSecondary = Color.White,
|
||||
onTertiary = Color.White,
|
||||
onBackground = Color(0xFF1C1B1F),
|
||||
onSurface = Color(0xFF1C1B1F),
|
||||
*/
|
||||
)
|
||||
|
||||
@Composable
|
||||
fun Simplecloudnotifier2Theme(
|
||||
darkTheme: Boolean = isSystemInDarkTheme(),
|
||||
// Dynamic color is available on Android 12+
|
||||
dynamicColor: Boolean = true,
|
||||
content: @Composable () -> Unit
|
||||
) {
|
||||
val colorScheme = when {
|
||||
dynamicColor && Build.VERSION.SDK_INT >= Build.VERSION_CODES.S -> {
|
||||
val context = LocalContext.current
|
||||
if (darkTheme) dynamicDarkColorScheme(context) else dynamicLightColorScheme(context)
|
||||
}
|
||||
|
||||
darkTheme -> DarkColorScheme
|
||||
else -> LightColorScheme
|
||||
}
|
||||
val view = LocalView.current
|
||||
if (!view.isInEditMode) {
|
||||
SideEffect {
|
||||
val window = (view.context as Activity).window
|
||||
window.statusBarColor = colorScheme.primary.toArgb()
|
||||
WindowCompat.getInsetsController(window, view).isAppearanceLightStatusBars = darkTheme
|
||||
}
|
||||
}
|
||||
|
||||
MaterialTheme(
|
||||
colorScheme = colorScheme,
|
||||
typography = Typography,
|
||||
content = content
|
||||
)
|
||||
}
|
@@ -0,0 +1,34 @@
|
||||
package com.blackforestbytes.simplecloudnotifier2.ui.theme
|
||||
|
||||
import androidx.compose.material3.Typography
|
||||
import androidx.compose.ui.text.TextStyle
|
||||
import androidx.compose.ui.text.font.FontFamily
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.unit.sp
|
||||
|
||||
// Set of Material typography styles to start with
|
||||
val Typography = Typography(
|
||||
bodyLarge = TextStyle(
|
||||
fontFamily = FontFamily.Default,
|
||||
fontWeight = FontWeight.Normal,
|
||||
fontSize = 16.sp,
|
||||
lineHeight = 24.sp,
|
||||
letterSpacing = 0.5.sp
|
||||
)
|
||||
/* Other default text styles to override
|
||||
titleLarge = TextStyle(
|
||||
fontFamily = FontFamily.Default,
|
||||
fontWeight = FontWeight.Normal,
|
||||
fontSize = 22.sp,
|
||||
lineHeight = 28.sp,
|
||||
letterSpacing = 0.sp
|
||||
),
|
||||
labelSmall = TextStyle(
|
||||
fontFamily = FontFamily.Default,
|
||||
fontWeight = FontWeight.Medium,
|
||||
fontSize = 11.sp,
|
||||
lineHeight = 16.sp,
|
||||
letterSpacing = 0.5.sp
|
||||
)
|
||||
*/
|
||||
)
|
9
android_v2/app/src/main/res/drawable/fas_bookmark.xml
Normal file
9
android_v2/app/src/main/res/drawable/fas_bookmark.xml
Normal file
@@ -0,0 +1,9 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="384dp"
|
||||
android:height="512dp"
|
||||
android:viewportWidth="384"
|
||||
android:viewportHeight="512">
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M0,48V487.7C0,501.1 10.9,512 24.3,512c5,0 9.9,-1.5 14,-4.4L192,400 345.7,507.6c4.1,2.9 9,4.4 14,4.4c13.4,0 24.3,-10.9 24.3,-24.3V48c0,-26.5 -21.5,-48 -48,-48H48C21.5,0 0,21.5 0,48z"/>
|
||||
</vector>
|
9
android_v2/app/src/main/res/drawable/fas_burger.xml
Normal file
9
android_v2/app/src/main/res/drawable/fas_burger.xml
Normal file
@@ -0,0 +1,9 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="512dp"
|
||||
android:height="512dp"
|
||||
android:viewportWidth="512"
|
||||
android:viewportHeight="512">
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M61.1,224C45,224 32,211 32,194.9c0,-1.9 0.2,-3.7 0.6,-5.6C37.9,168.3 78.8,32 256,32s218.1,136.3 223.4,157.3c0.5,1.9 0.6,3.7 0.6,5.6c0,16.1 -13,29.1 -29.1,29.1L61.1,224zM144,128a16,16 0,1 0,-32 0,16 16,0 1,0 32,0zM384,144a16,16 0,1 0,0 -32,16 16,0 1,0 0,32zM272,96a16,16 0,1 0,-32 0,16 16,0 1,0 32,0zM16,304c0,-26.5 21.5,-48 48,-48L448,256c26.5,0 48,21.5 48,48s-21.5,48 -48,48L64,352c-26.5,0 -48,-21.5 -48,-48zM32,400c0,-8.8 7.2,-16 16,-16L464,384c8.8,0 16,7.2 16,16v16c0,35.3 -28.7,64 -64,64L96,480c-35.3,0 -64,-28.7 -64,-64L32,400z"/>
|
||||
</vector>
|
9
android_v2/app/src/main/res/drawable/fas_computer.xml
Normal file
9
android_v2/app/src/main/res/drawable/fas_computer.xml
Normal file
@@ -0,0 +1,9 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="640dp"
|
||||
android:height="512dp"
|
||||
android:viewportWidth="640"
|
||||
android:viewportHeight="512">
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M384,96L384,320L64,320L64,96L384,96zM64,32C28.7,32 0,60.7 0,96L0,320c0,35.3 28.7,64 64,64L181.3,384l-10.7,32L96,416c-17.7,0 -32,14.3 -32,32s14.3,32 32,32L352,480c17.7,0 32,-14.3 32,-32s-14.3,-32 -32,-32L277.3,416l-10.7,-32L384,384c35.3,0 64,-28.7 64,-64L448,96c0,-35.3 -28.7,-64 -64,-64L64,32zM528,32c-26.5,0 -48,21.5 -48,48L480,432c0,26.5 21.5,48 48,48h64c26.5,0 48,-21.5 48,-48L640,80c0,-26.5 -21.5,-48 -48,-48L528,32zM544,96h32c8.8,0 16,7.2 16,16s-7.2,16 -16,16L544,128c-8.8,0 -16,-7.2 -16,-16s7.2,-16 16,-16zM528,176c0,-8.8 7.2,-16 16,-16h32c8.8,0 16,7.2 16,16s-7.2,16 -16,16L544,192c-8.8,0 -16,-7.2 -16,-16zM560,336a32,32 0,1 1,0 64,32 32,0 1,1 0,-64z"/>
|
||||
</vector>
|
9
android_v2/app/src/main/res/drawable/fas_gauge.xml
Normal file
9
android_v2/app/src/main/res/drawable/fas_gauge.xml
Normal file
@@ -0,0 +1,9 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="512dp"
|
||||
android:height="512dp"
|
||||
android:viewportWidth="512"
|
||||
android:viewportHeight="512">
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M0,256a256,256 0,1 1,512 0A256,256 0,1 1,0 256zM320,352c0,-26.9 -16.5,-49.9 -40,-59.3L280,88c0,-13.3 -10.7,-24 -24,-24s-24,10.7 -24,24L232,292.7c-23.5,9.5 -40,32.5 -40,59.3c0,35.3 28.7,64 64,64s64,-28.7 64,-64zM144,176a32,32 0,1 0,0 -64,32 32,0 1,0 0,64zM128,256a32,32 0,1 0,-64 0,32 32,0 1,0 64,0zM416,288a32,32 0,1 0,0 -64,32 32,0 1,0 0,64zM400,144a32,32 0,1 0,-64 0,32 32,0 1,0 64,0z"/>
|
||||
</vector>
|
9
android_v2/app/src/main/res/drawable/fas_gear.xml
Normal file
9
android_v2/app/src/main/res/drawable/fas_gear.xml
Normal file
@@ -0,0 +1,9 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="512dp"
|
||||
android:height="512dp"
|
||||
android:viewportWidth="512"
|
||||
android:viewportHeight="512">
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M495.9,166.6c3.2,8.7 0.5,18.4 -6.4,24.6l-43.3,39.4c1.1,8.3 1.7,16.8 1.7,25.4s-0.6,17.1 -1.7,25.4l43.3,39.4c6.9,6.2 9.6,15.9 6.4,24.6c-4.4,11.9 -9.7,23.3 -15.8,34.3l-4.7,8.1c-6.6,11 -14,21.4 -22.1,31.2c-5.9,7.2 -15.7,9.6 -24.5,6.8l-55.7,-17.7c-13.4,10.3 -28.2,18.9 -44,25.4l-12.5,57.1c-2,9.1 -9,16.3 -18.2,17.8c-13.8,2.3 -28,3.5 -42.5,3.5s-28.7,-1.2 -42.5,-3.5c-9.2,-1.5 -16.2,-8.7 -18.2,-17.8l-12.5,-57.1c-15.8,-6.5 -30.6,-15.1 -44,-25.4L83.1,425.9c-8.8,2.8 -18.6,0.3 -24.5,-6.8c-8.1,-9.8 -15.5,-20.2 -22.1,-31.2l-4.7,-8.1c-6.1,-11 -11.4,-22.4 -15.8,-34.3c-3.2,-8.7 -0.5,-18.4 6.4,-24.6l43.3,-39.4C64.6,273.1 64,264.6 64,256s0.6,-17.1 1.7,-25.4L22.4,191.2c-6.9,-6.2 -9.6,-15.9 -6.4,-24.6c4.4,-11.9 9.7,-23.3 15.8,-34.3l4.7,-8.1c6.6,-11 14,-21.4 22.1,-31.2c5.9,-7.2 15.7,-9.6 24.5,-6.8l55.7,17.7c13.4,-10.3 28.2,-18.9 44,-25.4l12.5,-57.1c2,-9.1 9,-16.3 18.2,-17.8C227.3,1.2 241.5,0 256,0s28.7,1.2 42.5,3.5c9.2,1.5 16.2,8.7 18.2,17.8l12.5,57.1c15.8,6.5 30.6,15.1 44,25.4l55.7,-17.7c8.8,-2.8 18.6,-0.3 24.5,6.8c8.1,9.8 15.5,20.2 22.1,31.2l4.7,8.1c6.1,11 11.4,22.4 15.8,34.3zM256,336a80,80 0,1 0,0 -160,80 80,0 1,0 0,160z"/>
|
||||
</vector>
|
9
android_v2/app/src/main/res/drawable/fas_key.xml
Normal file
9
android_v2/app/src/main/res/drawable/fas_key.xml
Normal file
@@ -0,0 +1,9 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="512dp"
|
||||
android:height="512dp"
|
||||
android:viewportWidth="512"
|
||||
android:viewportHeight="512">
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M336,352c97.2,0 176,-78.8 176,-176S433.2,0 336,0S160,78.8 160,176c0,18.7 2.9,36.8 8.3,53.7L7,391c-4.5,4.5 -7,10.6 -7,17v80c0,13.3 10.7,24 24,24h80c13.3,0 24,-10.7 24,-24V448h40c13.3,0 24,-10.7 24,-24V384h40c6.4,0 12.5,-2.5 17,-7l33.3,-33.3c16.9,5.4 35,8.3 53.7,8.3zM376,96a40,40 0,1 1,0 80,40 40,0 1,1 0,-80z"/>
|
||||
</vector>
|
@@ -0,0 +1,9 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="512dp"
|
||||
android:height="512dp"
|
||||
android:viewportWidth="512"
|
||||
android:viewportHeight="512">
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M49.9,27.8C15.1,12.7 -19.2,50.1 -1.2,83.5L68.1,212.2c4.4,8.3 12.6,13.8 21.9,15c0,0 0,0 0,0l176,22c3.4,0.4 6,3.3 6,6.7s-2.6,6.3 -6,6.7l-176,22s0,0 0,0c-9.3,1.2 -17.5,6.8 -21.9,15L-1.2,428.5c-18,33.4 16.3,70.8 51.1,55.7L491.8,292.7c32.1,-13.9 32.1,-59.5 0,-73.4L49.9,27.8z"/>
|
||||
</vector>
|
9
android_v2/app/src/main/res/drawable/fas_plus.xml
Normal file
9
android_v2/app/src/main/res/drawable/fas_plus.xml
Normal file
@@ -0,0 +1,9 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="448dp"
|
||||
android:height="512dp"
|
||||
android:viewportWidth="448"
|
||||
android:viewportHeight="512">
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M256,80c0,-17.7 -14.3,-32 -32,-32s-32,14.3 -32,32V224H48c-17.7,0 -32,14.3 -32,32s14.3,32 32,32H192V432c0,17.7 14.3,32 32,32s32,-14.3 32,-32V288H400c17.7,0 32,-14.3 32,-32s-14.3,-32 -32,-32H256V80z"/>
|
||||
</vector>
|
9
android_v2/app/src/main/res/drawable/fas_road.xml
Normal file
9
android_v2/app/src/main/res/drawable/fas_road.xml
Normal file
@@ -0,0 +1,9 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="576dp"
|
||||
android:height="512dp"
|
||||
android:viewportWidth="576"
|
||||
android:viewportHeight="512">
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M256,32L181.2,32c-27.1,0 -51.3,17.1 -60.3,42.6L3.1,407.2C1.1,413 0,419.2 0,425.4C0,455.5 24.5,480 54.6,480L256,480L256,416c0,-17.7 14.3,-32 32,-32s32,14.3 32,32v64L521.4,480c30.2,0 54.6,-24.5 54.6,-54.6c0,-6.2 -1.1,-12.4 -3.1,-18.2L455.1,74.6C446,49.1 421.9,32 394.8,32L320,32L320,96c0,17.7 -14.3,32 -32,32s-32,-14.3 -32,-32L256,32zM320,224v64c0,17.7 -14.3,32 -32,32s-32,-14.3 -32,-32L256,224c0,-17.7 14.3,-32 32,-32s32,14.3 32,32z"/>
|
||||
</vector>
|
9
android_v2/app/src/main/res/drawable/fas_sack.xml
Normal file
9
android_v2/app/src/main/res/drawable/fas_sack.xml
Normal file
@@ -0,0 +1,9 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="512dp"
|
||||
android:height="512dp"
|
||||
android:viewportWidth="512"
|
||||
android:viewportHeight="512">
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M192,96L320,96l47.4,-71.1C374.5,14.2 366.9,0 354.1,0L157.9,0c-12.8,0 -20.4,14.2 -13.3,24.9L192,96zM320,128L192,128c-3.8,2.5 -8.1,5.3 -13,8.4l0,0C122.3,172.7 0,250.9 0,416c0,53 43,96 96,96L416,512c53,0 96,-43 96,-96c0,-165.1 -122.3,-243.3 -179,-279.6c-4.8,-3.1 -9.2,-5.9 -13,-8.4z"/>
|
||||
</vector>
|
9
android_v2/app/src/main/res/drawable/fas_user.xml
Normal file
9
android_v2/app/src/main/res/drawable/fas_user.xml
Normal file
@@ -0,0 +1,9 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="448dp"
|
||||
android:height="512dp"
|
||||
android:viewportWidth="448"
|
||||
android:viewportHeight="512">
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M224,256A128,128 0,1 0,224 0a128,128 0,1 0,0 256zM178.3,304C79.8,304 0,383.8 0,482.3C0,498.7 13.3,512 29.7,512L418.3,512c16.4,0 29.7,-13.3 29.7,-29.7C448,383.8 368.2,304 269.7,304L178.3,304z"/>
|
||||
</vector>
|
170
android_v2/app/src/main/res/drawable/ic_launcher_background.xml
Normal file
170
android_v2/app/src/main/res/drawable/ic_launcher_background.xml
Normal file
@@ -0,0 +1,170 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="108dp"
|
||||
android:height="108dp"
|
||||
android:viewportWidth="108"
|
||||
android:viewportHeight="108">
|
||||
<path
|
||||
android:fillColor="#3DDC84"
|
||||
android:pathData="M0,0h108v108h-108z" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M9,0L9,108"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M19,0L19,108"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M29,0L29,108"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M39,0L39,108"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M49,0L49,108"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M59,0L59,108"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M69,0L69,108"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M79,0L79,108"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M89,0L89,108"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M99,0L99,108"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M0,9L108,9"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M0,19L108,19"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M0,29L108,29"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M0,39L108,39"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M0,49L108,49"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M0,59L108,59"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M0,69L108,69"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M0,79L108,79"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M0,89L108,89"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M0,99L108,99"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M19,29L89,29"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M19,39L89,39"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M19,49L89,49"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M19,59L89,59"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M19,69L89,69"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M19,79L89,79"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M29,19L29,89"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M39,19L39,89"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M49,19L49,89"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M59,19L59,89"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M69,19L69,89"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M79,19L79,89"
|
||||
android:strokeWidth="0.8"
|
||||
android:strokeColor="#33FFFFFF" />
|
||||
</vector>
|
@@ -0,0 +1,30 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:aapt="http://schemas.android.com/aapt"
|
||||
android:width="108dp"
|
||||
android:height="108dp"
|
||||
android:viewportWidth="108"
|
||||
android:viewportHeight="108">
|
||||
<path android:pathData="M31,63.928c0,0 6.4,-11 12.1,-13.1c7.2,-2.6 26,-1.4 26,-1.4l38.1,38.1L107,108.928l-32,-1L31,63.928z">
|
||||
<aapt:attr name="android:fillColor">
|
||||
<gradient
|
||||
android:endX="85.84757"
|
||||
android:endY="92.4963"
|
||||
android:startX="42.9492"
|
||||
android:startY="49.59793"
|
||||
android:type="linear">
|
||||
<item
|
||||
android:color="#44000000"
|
||||
android:offset="0.0" />
|
||||
<item
|
||||
android:color="#00000000"
|
||||
android:offset="1.0" />
|
||||
</gradient>
|
||||
</aapt:attr>
|
||||
</path>
|
||||
<path
|
||||
android:fillColor="#FFFFFF"
|
||||
android:fillType="nonZero"
|
||||
android:pathData="M65.3,45.828l3.8,-6.6c0.2,-0.4 0.1,-0.9 -0.3,-1.1c-0.4,-0.2 -0.9,-0.1 -1.1,0.3l-3.9,6.7c-6.3,-2.8 -13.4,-2.8 -19.7,0l-3.9,-6.7c-0.2,-0.4 -0.7,-0.5 -1.1,-0.3C38.8,38.328 38.7,38.828 38.9,39.228l3.8,6.6C36.2,49.428 31.7,56.028 31,63.928h46C76.3,56.028 71.8,49.428 65.3,45.828zM43.4,57.328c-0.8,0 -1.5,-0.5 -1.8,-1.2c-0.3,-0.7 -0.1,-1.5 0.4,-2.1c0.5,-0.5 1.4,-0.7 2.1,-0.4c0.7,0.3 1.2,1 1.2,1.8C45.3,56.528 44.5,57.328 43.4,57.328L43.4,57.328zM64.6,57.328c-0.8,0 -1.5,-0.5 -1.8,-1.2s-0.1,-1.5 0.4,-2.1c0.5,-0.5 1.4,-0.7 2.1,-0.4c0.7,0.3 1.2,1 1.2,1.8C66.5,56.528 65.6,57.328 64.6,57.328L64.6,57.328z"
|
||||
android:strokeWidth="1"
|
||||
android:strokeColor="#00000000" />
|
||||
</vector>
|
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<background android:drawable="@drawable/ic_launcher_background" />
|
||||
<foreground android:drawable="@drawable/ic_launcher_foreground" />
|
||||
<monochrome android:drawable="@drawable/ic_launcher_foreground" />
|
||||
</adaptive-icon>
|
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<background android:drawable="@drawable/ic_launcher_background" />
|
||||
<foreground android:drawable="@drawable/ic_launcher_foreground" />
|
||||
<monochrome android:drawable="@drawable/ic_launcher_foreground" />
|
||||
</adaptive-icon>
|
BIN
android_v2/app/src/main/res/mipmap-hdpi/ic_launcher.webp
Normal file
BIN
android_v2/app/src/main/res/mipmap-hdpi/ic_launcher.webp
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.4 KiB |
BIN
android_v2/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp
Normal file
BIN
android_v2/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp
Normal file
Binary file not shown.
After Width: | Height: | Size: 2.8 KiB |
BIN
android_v2/app/src/main/res/mipmap-mdpi/ic_launcher.webp
Normal file
BIN
android_v2/app/src/main/res/mipmap-mdpi/ic_launcher.webp
Normal file
Binary file not shown.
After Width: | Height: | Size: 982 B |
BIN
android_v2/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp
Normal file
BIN
android_v2/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.7 KiB |
BIN
android_v2/app/src/main/res/mipmap-xhdpi/ic_launcher.webp
Normal file
BIN
android_v2/app/src/main/res/mipmap-xhdpi/ic_launcher.webp
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.9 KiB |
BIN
android_v2/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp
Normal file
BIN
android_v2/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp
Normal file
Binary file not shown.
After Width: | Height: | Size: 3.8 KiB |
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user