Rename top level directories

This commit is contained in:
Elias Projahn 2020-04-24 21:55:17 +02:00
parent 256bda1b72
commit 674ce19414
90 changed files with 0 additions and 0 deletions

View file

@ -0,0 +1,68 @@
def localProperties = new Properties()
def localPropertiesFile = rootProject.file('local.properties')
if (localPropertiesFile.exists()) {
localPropertiesFile.withReader('UTF-8') { reader ->
localProperties.load(reader)
}
}
def flutterRoot = localProperties.getProperty('flutter.sdk')
if (flutterRoot == null) {
throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.")
}
def flutterVersionCode = localProperties.getProperty('flutter.versionCode')
if (flutterVersionCode == null) {
flutterVersionCode = '1'
}
def flutterVersionName = localProperties.getProperty('flutter.versionName')
if (flutterVersionName == null) {
flutterVersionName = '1.0'
}
apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle"
android {
compileSdkVersion 29
sourceSets {
main.java.srcDirs += 'src/main/kotlin'
}
lintOptions {
disable 'InvalidPackage'
}
defaultConfig {
applicationId "de.johrpan.musicus"
minSdkVersion 21
targetSdkVersion 29
versionCode flutterVersionCode.toInteger()
versionName flutterVersionName
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
// TODO: Add your own signing config for the release build.
// Signing with the debug keys for now, so `flutter run --release` works.
signingConfig signingConfigs.debug
// See https://github.com/ryanheise/audio_service/blob/master/README.md#android-setup
shrinkResources false
}
}
}
flutter {
source '../..'
}
dependencies {
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
testImplementation 'junit:junit:4.12'
androidTestImplementation 'androidx.test:runner:1.1.1'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.1'
}

View file

@ -0,0 +1,7 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="de.johrpan.musicus">
<!-- Flutter needs it to communicate with the running application
to allow setting breakpoints, to provide hot reload, etc.
-->
<uses-permission android:name="android.permission.INTERNET"/>
</manifest>

View file

@ -0,0 +1,43 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="de.johrpan.musicus">
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<application
android:name="io.flutter.app.FlutterApplication"
android:label="Musicus"
android:icon="@mipmap/ic_launcher"
android:roundIcon="@mipmap/ic_launcher_round">
<activity
android:name=".MainActivity"
android:launchMode="singleTop"
android:theme="@style/LaunchTheme"
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
android:hardwareAccelerated="true"
android:windowSoftInputMode="adjustResize">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<service android:name="com.ryanheise.audioservice.AudioService">
<intent-filter>
<action android:name="android.media.browse.MediaBrowserService" />
</intent-filter>
</service>
<receiver android:name="androidx.media.session.MediaButtonReceiver" >
<intent-filter>
<action android:name="android.intent.action.MEDIA_BUTTON" />
</intent-filter>
</receiver>
<meta-data
android:name="flutterEmbedding"
android:value="2" />
</application>
</manifest>

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

View file

@ -0,0 +1,240 @@
package de.johrpan.musicus
import android.app.Activity
import android.content.Intent
import android.net.Uri
import android.provider.DocumentsContract
import androidx.annotation.NonNull
import io.flutter.embedding.android.FlutterActivity
import io.flutter.embedding.engine.FlutterEngine
import io.flutter.plugin.common.MethodChannel
import io.flutter.plugins.GeneratedPluginRegistrant
class Document(private val id: String, private val name: String, private val parentId: String?, private val isDirectory: Boolean) {
fun toMap(): Map<String, Any?> {
return mapOf(
"id" to id,
"name" to name,
"parentId" to parentId,
"isDirectory" to isDirectory
)
}
}
class MainActivity : FlutterActivity() {
private val CHANNEL = "de.johrpan.musicus/platform"
private val AODT_REQUEST = 0
private var aodtResult: MethodChannel.Result? = null
override fun configureFlutterEngine(@NonNull flutterEngine: FlutterEngine) {
GeneratedPluginRegistrant.registerWith(flutterEngine)
MethodChannel(flutterEngine.dartExecutor.binaryMessenger, CHANNEL).setMethodCallHandler { call, result ->
if (call.method == "openTree") {
aodtResult = result
// We will get the result within onActivityResult
openTree()
} else if (call.method == "getChildren") {
val treeUri = Uri.parse(call.argument<String>("treeUri"))
val parentId = call.argument<String>("parentId")
val children = getChildren(treeUri, parentId)
result.success(children.map { it.toMap() })
} else if (call.method == "readFile") {
val treeUri = Uri.parse(call.argument<String>("treeUri"))
val id = call.argument<String>("id")!!
result.success(readFile(treeUri, id))
} else if (call.method == "getUriByName") {
val treeUri = Uri.parse(call.argument<String>("treeUri"))
val parentId = call.argument<String>("parentId")!!
val fileName = call.argument<String>("fileName")!!
result.success(getUriByName(treeUri, parentId, fileName).toString())
} else if (call.method == "readFileByName") {
val treeUri = Uri.parse(call.argument<String>("treeUri"))
val parentId = call.argument<String>("parentId")!!
val fileName = call.argument<String>("fileName")!!
result.success(readFileByName(treeUri, parentId, fileName))
} else if (call.method == "writeFileByName") {
val treeUri = Uri.parse(call.argument<String>("treeUri"))
val parentId = call.argument<String>("parentId")!!
val fileName = call.argument<String>("fileName")!!
val content = call.argument<String>("content")!!
writeFileByName(treeUri, parentId, fileName, content)
result.success(null)
} else {
result.notImplemented()
}
}
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
if (requestCode == AODT_REQUEST) {
if (resultCode == Activity.RESULT_OK && data?.data != null) {
// Drop all old URIs
contentResolver.persistedUriPermissions.forEach {
contentResolver.releasePersistableUriPermission(it.uri, Intent.FLAG_GRANT_WRITE_URI_PERMISSION)
}
// We already checked for null
val uri = data.data!!
contentResolver.takePersistableUriPermission(uri, Intent.FLAG_GRANT_WRITE_URI_PERMISSION)
aodtResult?.success(uri.toString())
} else {
aodtResult?.success(null)
}
}
}
/**
* Open a document tree using the storage access framework
*
* The result is handled within [onActivityResult]
*/
private fun openTree() {
val intent = Intent(Intent.ACTION_OPEN_DOCUMENT_TREE)
intent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION)
intent.addFlags(Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION)
startActivityForResult(intent, AODT_REQUEST)
}
/**
* List children of a directory
*
* @param treeUri The treeUri from the ACTION_OPEN_DOCUMENT_TREE request
* @param parentId Document ID of the parent directory or null for the top level directory
* @return List of directories and files within the directory
*/
private fun getChildren(treeUri: Uri, parentId: String?): List<Document> {
val realParentId = parentId ?: DocumentsContract.getTreeDocumentId(treeUri)
val children = ArrayList<Document>()
val childrenUri = DocumentsContract.buildChildDocumentsUriUsingTree(treeUri, realParentId)
val cursor = contentResolver.query(
childrenUri,
arrayOf(DocumentsContract.Document.COLUMN_DOCUMENT_ID,
DocumentsContract.Document.COLUMN_DISPLAY_NAME,
DocumentsContract.Document.COLUMN_MIME_TYPE),
null, null, null)
if (cursor != null) {
while (cursor.moveToNext()) {
val id = cursor.getString(0)
val name = cursor.getString(1)
val isDirectory = cursor.getString(2) == DocumentsContract.Document.MIME_TYPE_DIR
// Use parentId here to let the consumer know that we are at the top level.
children.add(Document(id, name, parentId, isDirectory))
}
cursor.close()
}
return children
}
/**
* Look for a file by name
*
* @param treeUri The treeUri from the ACTION_OPEN_DOCUMENT_TREE request
* @param parentId The directory in which the file is searched for
* @param fileName Name of the file
* @return The URI of the file or null
*/
private fun getUriByName(treeUri: Uri, parentId: String, fileName: String): Uri? {
var uri: Uri? = null
val childrenUri = DocumentsContract.buildChildDocumentsUriUsingTree(treeUri, parentId)
val projection = arrayOf(DocumentsContract.Document.COLUMN_DOCUMENT_ID, DocumentsContract.Document.COLUMN_DISPLAY_NAME)
// The file system provider doesn't support a select clause.
val cursor = contentResolver.query(childrenUri, projection, null, null, null)
if (cursor != null) {
while (cursor.moveToNext()) {
val id = cursor.getString(0)
val name = cursor.getString(1)
if (name == fileName) {
uri = DocumentsContract.buildDocumentUriUsingTree(treeUri, id)
break
}
}
cursor.close()
}
return uri
}
/**
* Read content of a file
*
* @param treeUri The URI from ACTION_OPEN_DOCUMENT_TREE
* @param id The document ID of the file
* @return File content or null
*/
private fun readFile(treeUri: Uri, id: String): String? {
val uri = DocumentsContract.buildDocumentUriUsingTree(treeUri, id)
// TODO: Handle errors.
val input = contentResolver.openInputStream(uri)!!
val result = input.reader().readText()
input.close()
return result
}
/**
* Read content of a file by name
*
* @param treeUri The URI from ACTION_OPEN_DOCUMENT_TREE
* @param parentId Document ID of the parent directory
* @param fileName Name of the file
* @return File content or null
*/
private fun readFileByName(treeUri: Uri, parentId: String, fileName: String): String? {
var uri = getUriByName(treeUri, parentId, fileName)
return if (uri != null) {
// TODO: Handle errors.
val input = contentResolver.openInputStream(uri)!!
val result = input.reader().readText()
input.close()
return result
} else {
null
}
}
/**
* Write to file by name
*
* The file will always have the MIME type application/json.
*
* @param treeUri The URI from ACTION_OPEN_DOCUMENT_TREE
* @param parentId Document ID of the parent directory
* @param fileName Name of the file
* @param content Content to write
* @return File content or null
*/
private fun writeFileByName(treeUri: Uri, parentId: String, fileName: String, content: String) {
var uri = getUriByName(treeUri, parentId, fileName);
if (uri == null) {
val parentUri = DocumentsContract.buildDocumentUriUsingTree(treeUri, parentId)
uri = DocumentsContract.createDocument(contentResolver, parentUri, "application/json", fileName)
}
// TODO: Handle errors.
val output = contentResolver.openOutputStream(uri!!)!!;
val writer = output.writer()
writer.write(content)
writer.close()
output.close()
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 674 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 140 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 272 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 102 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 485 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 108 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 159 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 92 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 162 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 288 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 114 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 202 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 547 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 196 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 244 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 488 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 244 B

View file

@ -0,0 +1,11 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="108dp"
android:height="108dp"
android:viewportWidth="108"
android:viewportHeight="108">
<path
android:pathData="m45.993,37.589c-1.147,6.587 -2.628,14.34 -4.415,23.149 -1.222,-1.066 -2.952,-1.735 -4.877,-1.735 -3.701,0 -6.701,2.462 -6.701,5.498s3,5.498 6.701,5.498 6.101,-1.669 6.701,-5.498c0.858,-6.02 1.602,-10.357 2.94,-18.602h0.195c2.249,4.725 4.562,9.879 6.941,15.456l2.43,-4.965c-2.647,-5.62 -5.452,-11.86 -8.432,-18.802zM68.7,37.589c-4.441,9.091 -9.305,19.012 -13.563,27.716 0.495,1.106 0.494,1.094 1.631,1.863 3.214,-7.358 6.516,-14.404 9.904,-21.137l0.175,0.022c1.149,8.652 1.97,15.734 2.464,21.246 0.451,-0.087 1.185,-0.131 2.203,-0.131 1.207,0 2.036,0.043 2.486,0.131 -1.629,-9.772 -3.023,-19.675 -4.187,-29.709z"
android:strokeWidth=".80618"
android:fillColor="#ffc107" />
</vector>

View file

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@color/background" />
<foreground android:drawable="@drawable/ic_launcher_foreground" />
</adaptive-icon>

View file

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@color/background" />
<foreground android:drawable="@drawable/ic_launcher_foreground" />
</adaptive-icon>

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

View file

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources>
<color name="background">#303030</color>
</resources>

View file

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources>
<style name="LaunchTheme" parent="@android:style/Theme.Black.NoTitleBar">
<item name="android:windowBackground">@color/background</item>
</style>
</resources>

View file

@ -0,0 +1,7 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="de.johrpan.musicus">
<!-- Flutter needs it to communicate with the running application
to allow setting breakpoints, to provide hot reload, etc.
-->
<uses-permission android:name="android.permission.INTERNET"/>
</manifest>