Add Manual Consoles on Android

This commit is contained in:
Florian Märkl 2019-10-25 18:58:34 +02:00
parent 83777c4fa4
commit 6baf8e9c2a
No known key found for this signature in database
GPG key ID: 125BC8A5A6A1E857
15 changed files with 374 additions and 160 deletions

View file

@ -1,5 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="com.metallic.chiaki">
<uses-permission android:name="android.permission.INTERNET" />
@ -11,7 +12,8 @@
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
android:theme="@style/AppTheme"
tools:ignore="GoogleAppIndexingWarning">
<activity android:name=".main.MainActivity"
android:configChanges="keyboard|keyboardHidden|orientation|screenSize">
@ -30,11 +32,6 @@
<activity
android:name=".settings.SettingsActivity" />
<activity
android:name=".TestStartActivity"
android:theme="@style/MageTheme"
android:configChanges="keyboard|keyboardHidden|orientation|screenSize"/>
<activity
android:name=".regist.RegistActivity"
android:theme="@style/MageTheme"
@ -45,6 +42,11 @@
android:name=".regist.RegistExecuteActivity"
android:theme="@style/MageTheme"
android:configChanges="keyboard|keyboardHidden|orientation|screenSize" />
<activity
android:name=".manualconsole.AddManualConsoleActivity"
android:theme="@style/MageTheme"
android:configChanges="keyboard|keyboardHidden|orientation|screenSize" />
</application>
</manifest>

View file

@ -1,86 +0,0 @@
/*
* This file is part of Chiaki.
*
* Chiaki is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Chiaki is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Chiaki. If not, see <https://www.gnu.org/licenses/>.
*/
package com.metallic.chiaki
import android.content.Context
import android.content.Intent
import android.os.Bundle
import android.util.Base64
import android.view.View
import android.view.Window
import androidx.appcompat.app.AppCompatActivity
import androidx.core.content.edit
import androidx.core.widget.addTextChangedListener
import com.metallic.chiaki.common.Preferences
import com.metallic.chiaki.common.ext.RevealActivity
import com.metallic.chiaki.lib.ConnectInfo
import com.metallic.chiaki.stream.StreamActivity
import kotlinx.android.synthetic.main.activity_test_start.*
class TestStartActivity : AppCompatActivity(), RevealActivity
{
override val revealIntent: Intent get() = intent
override val revealRootLayout: View get() = rootLayout
override val revealWindow: Window get() = window
override fun onCreate(savedInstanceState: Bundle?)
{
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_test_start)
handleReveal()
val prefs = getPreferences(Context.MODE_PRIVATE)
hostEditText.setText(prefs.getString("debug_host", ""))
registKeyEditText.setText(prefs.getString("debug_regist_key", ""))
morningEditText.setText(prefs.getString("debug_morning", ""))
hostEditText.addTextChangedListener {
prefs.edit {
putString("debug_host", it?.toString())
}
}
registKeyEditText.addTextChangedListener {
prefs.edit {
putString("debug_regist_key", it?.toString())
}
}
morningEditText.addTextChangedListener {
prefs.edit {
putString("debug_morning", it?.toString())
}
}
startButton.setOnClickListener {
val registKeyBase = registKeyEditText.text.toString().toByteArray(Charsets.US_ASCII)
val registKey = registKeyBase + ByteArray(0x10 - registKeyBase.size) { 0 }
val morning = Base64.decode(morningEditText.text.toString(), Base64.DEFAULT)
val connectInfo = ConnectInfo(hostEditText.text.toString(),
registKey,
morning,
Preferences(this).videoProfile)
Intent(this, StreamActivity::class.java).let {
it.putExtra(StreamActivity.EXTRA_CONNECT_INFO, connectInfo)
startActivity(it)
}
}
}
}

View file

@ -18,7 +18,6 @@
package com.metallic.chiaki.main
import android.app.ActivityOptions
import android.app.AlertDialog
import android.content.Intent
import android.os.Bundle
import android.view.Menu
@ -29,7 +28,6 @@ import androidx.lifecycle.ViewModelProviders
import androidx.recyclerview.widget.LinearLayoutManager
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import com.metallic.chiaki.R
import com.metallic.chiaki.TestStartActivity
import com.metallic.chiaki.common.DiscoveredDisplayHost
import com.metallic.chiaki.common.DisplayHost
import com.metallic.chiaki.common.Preferences
@ -38,7 +36,7 @@ import com.metallic.chiaki.common.ext.viewModelFactory
import com.metallic.chiaki.common.getDatabase
import com.metallic.chiaki.lib.ConnectInfo
import com.metallic.chiaki.lib.DiscoveryHost
import com.metallic.chiaki.lib.RegistEventSuccess
import com.metallic.chiaki.manualconsole.AddManualConsoleActivity
import com.metallic.chiaki.regist.RegistActivity
import com.metallic.chiaki.settings.SettingsActivity
import com.metallic.chiaki.stream.StreamActivity
@ -153,7 +151,7 @@ class MainActivity : AppCompatActivity()
private fun addManualConsole()
{
Intent(this, TestStartActivity::class.java).also {
Intent(this, AddManualConsoleActivity::class.java).also {
it.putRevealExtra(addManualButton, rootLayout)
startActivity(it, ActivityOptions.makeSceneTransitionAnimation(this).toBundle())
}

View file

@ -0,0 +1,106 @@
/*
* This file is part of Chiaki.
*
* Chiaki is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Chiaki is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Chiaki. If not, see <https://www.gnu.org/licenses/>.
*/
package com.metallic.chiaki.manualconsole
import android.content.Intent
import android.os.Bundle
import android.view.View
import android.view.Window
import android.widget.AdapterView
import android.widget.AdapterView.OnItemSelectedListener
import android.widget.ArrayAdapter
import androidx.appcompat.app.AppCompatActivity
import androidx.lifecycle.Observer
import androidx.lifecycle.ViewModelProviders
import com.metallic.chiaki.R
import com.metallic.chiaki.common.ManualHost
import com.metallic.chiaki.common.RegisteredHost
import com.metallic.chiaki.common.ext.RevealActivity
import com.metallic.chiaki.common.ext.viewModelFactory
import com.metallic.chiaki.common.getDatabase
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.disposables.CompositeDisposable
import io.reactivex.rxkotlin.addTo
import kotlinx.android.synthetic.main.activity_add_manual.*
class AddManualConsoleActivity: AppCompatActivity(), RevealActivity
{
override val revealIntent: Intent get() = intent
override val revealRootLayout: View get() = rootLayout
override val revealWindow: Window get() = window
private lateinit var viewModel: AddManualConsoleViewModel
private val disposable = CompositeDisposable()
override fun onCreate(savedInstanceState: Bundle?)
{
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_add_manual)
handleReveal()
viewModel = ViewModelProviders
.of(this, viewModelFactory { AddManualConsoleViewModel(getDatabase(this)) })
.get(AddManualConsoleViewModel::class.java)
viewModel.selectedRegisteredHost.observe(this, Observer {
registeredHostTextView.setText(titleForRegisteredHost(it))
})
viewModel.registeredHosts.observe(this, Observer { hosts ->
registeredHostTextView.setAdapter(ArrayAdapter<String>(this, R.layout.dropdown_menu_popup_item,
hosts.map { titleForRegisteredHost(it) }))
registeredHostTextView.onItemClickListener = object: AdapterView.OnItemClickListener {
override fun onItemClick(parent: AdapterView<*>?, view: View?, position: Int, id: Long)
{
if(position >= hosts.size)
return
val host = hosts[position]
viewModel.selectedRegisteredHost.value = host
}
}
})
saveButton.setOnClickListener { saveHost() }
}
private fun titleForRegisteredHost(registeredHost: RegisteredHost?) =
if(registeredHost == null)
getString(R.string.add_manual_regist_on_connect)
else
"${registeredHost.ps4Nickname ?: ""} (${registeredHost.ps4Mac})"
private fun saveHost()
{
val host = hostEditText.text.toString().trim()
if(host.isEmpty())
{
hostEditText.error = getString(R.string.entered_host_invalid)
return
}
saveButton.isEnabled = false
viewModel.saveHost(host)
.observeOn(AndroidSchedulers.mainThread())
.subscribe {
finish()
}
.addTo(disposable)
}
}

View file

@ -0,0 +1,48 @@
/*
* This file is part of Chiaki.
*
* Chiaki is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Chiaki is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Chiaki. If not, see <https://www.gnu.org/licenses/>.
*/
package com.metallic.chiaki.manualconsole
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import com.metallic.chiaki.common.AppDatabase
import com.metallic.chiaki.common.ManualHost
import com.metallic.chiaki.common.RegisteredHost
import com.metallic.chiaki.common.ext.toLiveData
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.schedulers.Schedulers
class AddManualConsoleViewModel(val database: AppDatabase): ViewModel()
{
val registeredHosts by lazy {
database.registeredHostDao().getAll().observeOn(AndroidSchedulers.mainThread())
.doOnNext { hosts ->
val selectedHost = selectedRegisteredHost.value
if(selectedHost != null)
selectedRegisteredHost.value = hosts.firstOrNull { it.id == selectedHost.id }
}
.map { listOf(null) + it }
.toLiveData()
}
var selectedRegisteredHost = MutableLiveData<RegisteredHost?>(null)
fun saveHost(host: String) =
database.manualHostDao()
.insert(ManualHost(host = host, registeredHost = selectedRegisteredHost.value?.id))
.subscribeOn(Schedulers.io())
}

View file

@ -20,7 +20,6 @@ package com.metallic.chiaki.regist
import android.content.Intent
import android.os.Bundle
import android.util.Base64
import android.util.Log
import android.view.View
import android.view.Window
import androidx.appcompat.app.AppCompatActivity
@ -112,7 +111,7 @@ class RegistActivity: AppCompatActivity(), RevealActivity
val pin = pinEditText.text.toString()
val pinValid = pin.length == PIN_LENGTH
hostEditText.error = if(!hostValid) getString(R.string.regist_host_invalid) else null
hostEditText.error = if(!hostValid) getString(R.string.entered_host_invalid) else null
psnIdEditText.error =
if(!psnIdValid)
getString(when(ps4Version)

View file

@ -55,9 +55,6 @@ class RegistExecuteActivity: AppCompatActivity()
.of(this, viewModelFactory { RegistExecuteViewModel(getDatabase(this)) })
.get(RegistExecuteViewModel::class.java)
showDuplicateDialog()
return
logTextView.setHorizontallyScrolling(true)
logTextView.movementMethod = ScrollingMovementMethod()
viewModel.logText.observe(this, Observer {

View file

@ -28,7 +28,6 @@ import com.metallic.chiaki.common.ext.toLiveData
import com.metallic.chiaki.lib.*
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.disposables.CompositeDisposable
import io.reactivex.functions.Action
import io.reactivex.rxkotlin.addTo
import io.reactivex.schedulers.Schedulers
@ -113,7 +112,7 @@ class RegistExecuteViewModel(val database: AppDatabase): ViewModel()
.andThen(dao.insert(registeredHost))
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe { _ ->
.subscribe { _ -> /* No, IntelliJ, this "_ ->" IS necessary. */
Log.i("RegistExecute", "Registered Host saved in db")
_state.value = State.SUCCESSFUL
}

View file

@ -0,0 +1,23 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="505dp"
android:height="128dp"
android:viewportWidth="133.61458"
android:viewportHeight="33.86667">
<path
android:pathData="M15.6,3.81 L9.139,14.681L96.139,14.681l0,-1.98c-0.001,-2.013 1.629,-3.646 3.64,-3.647l9.048,0L108.827,3.81ZM6.461,19.186 L-0,30.057L108.827,30.057L108.827,24.812l-9.048,0c-2.011,-0.001 -3.64,-1.634 -3.64,-3.647l0,-1.979z"
android:strokeAlpha="1"
android:strokeWidth="53.1311"
android:fillColor="#000000"
android:strokeColor="#00000000"
android:fillAlpha="1"/>
<path
android:pathData="m112.469,0l0,12.7l-12.688,0l0,8.467l12.688,0l0,12.7l8.458,0l0,-12.7l12.688,0l0,-8.467l-12.688,0l0,-12.7z"
android:strokeAlpha="1"
android:strokeLineJoin="round"
android:strokeWidth="5.29167"
android:fillColor="#000000"
android:strokeColor="#00000000"
android:fillType="nonZero"
android:fillAlpha="1"
android:strokeLineCap="round"/>
</vector>

View file

@ -0,0 +1,83 @@
<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/rootLayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="?android:attr/windowBackground"
android:scrollbars="none">
<androidx.constraintlayout.widget.ConstraintLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="16dp"
android:animateLayoutChanges="true">
<ImageView
android:id="@+id/iconImageView"
android:layout_width="256dp"
android:layout_height="64dp"
android:src="@drawable/ic_add_manual"
android:layout_marginLeft="16dp"
android:layout_marginRight="16dp"
android:tint="?attr/colorOnPrimary"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
android:layout_marginTop="16dp"/>
<com.google.android.material.textview.MaterialTextView
android:id="@+id/titleTextView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/title_add_manual"
android:textSize="32sp"
android:gravity="center"
android:layout_marginTop="16dp"
app:layout_constraintTop_toBottomOf="@id/iconImageView"
android:textAppearance="?attr/textAppearanceHeadline1"/>
<com.google.android.material.textfield.TextInputLayout
android:id="@+id/hostTextInputLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="@string/hint_regist_host"
app:startIconDrawable="@drawable/ic_host"
app:layout_constraintTop_toBottomOf="@id/titleTextView"
android:layout_marginTop="32dp">
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/hostEditText"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="textNoSuggestions|textVisiblePassword"
android:maxLines="1"/>
</com.google.android.material.textfield.TextInputLayout>
<com.google.android.material.textfield.TextInputLayout
android:id="@+id/registeredHostTextInputLayout"
style="@style/MageTheme.TextInputStyle.ExposedDropdownMenu"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="@string/hint_add_manual_regist_host"
app:startIconDrawable="@drawable/ic_register"
app:layout_constraintTop_toBottomOf="@id/hostTextInputLayout"
android:layout_marginTop="32dp">
<AutoCompleteTextView
android:id="@+id/registeredHostTextView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:editable="false"
android:maxLines="1" /> <!-- editable is deprecated, but there is no alternative -->
</com.google.android.material.textfield.TextInputLayout>
<com.google.android.material.button.MaterialButton
android:id="@+id/saveButton"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constraintTop_toBottomOf="@id/registeredHostTextInputLayout"
style="@style/MageTheme.Button"
android:text="@string/action_add_manual_save"
android:layout_marginTop="32dp" />
</androidx.constraintlayout.widget.ConstraintLayout>
</ScrollView>

View file

@ -1,56 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/rootLayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="?android:attr/windowBackground"
tools:context=".main.MainActivity">
<EditText
android:id="@+id/hostEditText"
android:layout_width="200dp"
android:layout_height="wrap_content"
android:hint="Host"
app:layout_constraintBottom_toTopOf="@+id/registKeyEditText"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_chainStyle="packed"/>
<EditText
android:id="@+id/registKeyEditText"
android:layout_width="200dp"
android:layout_height="wrap_content"
android:hint="Regist Key"
app:layout_constraintBottom_toTopOf="@+id/morningEditText"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="@+id/hostEditText" />
<EditText
android:id="@+id/morningEditText"
android:layout_width="200dp"
android:layout_height="wrap_content"
android:hint="Morning (base64)"
app:layout_constraintBottom_toTopOf="@+id/startButton"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="@+id/registKeyEditText" />
<androidx.appcompat.widget.AppCompatButton
android:id="@+id/startButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Start"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="@+id/morningEditText" />
</androidx.constraintlayout.widget.ConstraintLayout>

View file

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="16dp"
android:ellipsize="end"
android:maxLines="1"
android:textAppearance="?attr/textAppearanceSubtitle1"/>

View file

@ -35,7 +35,7 @@
<string name="hint_regist_psn_account_id">PSN Account ID (8 bytes, base64)</string>
<string name="hint_regist_pin">PIN</string>
<string name="action_regist">Register</string>
<string name="regist_host_invalid">Please enter a valid host name</string>
<string name="entered_host_invalid">Please enter a valid host name</string>
<string name="regist_psn_online_id_invalid">Please enter a valid PSN ID</string>
<string name="regist_psn_account_id_invalid">Please enter a valid 8-byte Account ID in Base64</string>
<string name="regist_pin_invalid">Please enter a valid %d-digit PIN</string>
@ -45,6 +45,10 @@
<string name="alert_regist_duplicate">The console with MAC %s has already been registered. Should the previous record be overwritten?</string>
<string name="action_regist_overwrite">Overwrite</string>
<string name="action_regist_discard">Cancel</string>
<string name="title_add_manual">Add Console Manually</string>
<string name="action_add_manual_save">Save</string>
<string name="hint_add_manual_regist_host">Registered Console</string>
<string name="add_manual_regist_on_connect">Register on first Connection</string>
<string name="preferences_category_title_general">General</string>
<string name="preferences_category_title_stream">Stream</string>
<string name="preferences_registered_hosts_title">Registered Consoles</string>

View file

@ -77,6 +77,14 @@
<item name="boxBackgroundColor">?attr/colorPrimaryDark</item>
</style>
<style name="MageTheme.TextInputStyle.ExposedDropdownMenu" parent="Widget.MaterialComponents.TextInputLayout.FilledBox.ExposedDropdownMenu">
<item name="hintTextColor">?attr/colorAccent</item>
<item name="boxCornerRadiusTopStart">16dp</item>
<item name="boxCornerRadiusTopEnd">16dp</item>
<item name="boxStrokeColor">@color/mage_text_input_box_stroke</item>
<item name="boxBackgroundColor">?attr/colorPrimaryDark</item>
</style>
<style name="MageTheme.Button" parent="Widget.MaterialComponents.Button">
<item name="tint">?attr/colorOnSecondary</item>
<item name="android:backgroundTint">?attr/colorSecondary</item>

81
assets/add_console.svg Normal file
View file

@ -0,0 +1,81 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
sodipodi:docname="add_console.svg"
inkscape:version="1.0beta1 (5c3063637d, 2019-10-15)"
id="svg965"
version="1.1"
viewBox="0 0 133.61458 33.866667"
height="128"
width="505">
<defs
id="defs959" />
<sodipodi:namedview
inkscape:guide-bbox="true"
showguides="true"
inkscape:document-rotation="0"
inkscape:lockguides="true"
inkscape:object-paths="true"
inkscape:window-maximized="1"
inkscape:window-y="15"
inkscape:window-x="1920"
inkscape:window-height="1048"
inkscape:window-width="1918"
units="px"
showgrid="false"
inkscape:current-layer="layer1"
inkscape:document-units="mm"
inkscape:cy="95.042315"
inkscape:cx="242.99039"
inkscape:zoom="1.979899"
inkscape:pageshadow="2"
inkscape:pageopacity="0.0"
borderopacity="1.0"
bordercolor="#666666"
pagecolor="#ffffff"
id="base" />
<metadata
id="metadata962">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<g
transform="translate(0,-263.13332)"
id="layer1"
inkscape:groupmode="layer"
inkscape:label="Ebene 1">
<g
transform="matrix(1.3766446,0,0,1.3780225,-1.5050122e-6,-108.03923)"
id="g936">
<path
sodipodi:nodetypes="cccccccccccccccc"
inkscape:connector-curvature="0"
transform="matrix(0.26458333,0,0,0.26458333,0,264.7064)"
d="M 42.828125,28.005859 25.089844,57.822266 H 263.94727 v -5.429688 c -0.002,-5.521857 4.47228,-10.000119 9.99414,-10.003906 h 24.83984 V 28.005859 Z M 17.738281,70.179688 0,99.994141 H 298.78125 V 85.609375 h -24.83984 c -5.52109,-0.0038 -9.99467,-4.480859 -9.99414,-10.001953 v -5.427734 z"
style="fill:#000000;fill-opacity:1;stroke:none;stroke-width:53.1311;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="path950" />
<g
style="opacity:1"
id="g859">
<path
inkscape:connector-curvature="0"
id="path863"
d="m 81.697855,269.35159 v 9.21598 h -9.216493 v 6.14433 h 9.216493 v 9.21597 h 6.143811 v -9.21597 h 9.21649 v -6.14433 h -9.21649 v -9.21598 z"
style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-variant-east-asian:normal;font-feature-settings:normal;font-variation-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;shape-margin:0;inline-size:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:5.29167;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:stroke markers fill;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate;stop-color:#000000;stop-opacity:1" />
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 4.1 KiB