diff --git a/android/app/build.gradle.kts b/android/app/build.gradle.kts index cb0bb9771..1b88f67f8 100644 --- a/android/app/build.gradle.kts +++ b/android/app/build.gradle.kts @@ -1,6 +1,8 @@ plugins { id("com.android.application") id("org.jetbrains.kotlin.android") + id("com.google.devtools.ksp") + id("com.google.dagger.hilt.android") } android { @@ -24,7 +26,7 @@ android { } composeOptions { - kotlinCompilerExtensionVersion = "1.5.4" + kotlinCompilerExtensionVersion = "1.5.7" } buildTypes { @@ -64,6 +66,10 @@ dependencies { implementation("com.github.alorma:compose-settings-storage-preferences:1.0.3") implementation("com.google.accompanist:accompanist-permissions:0.33.2-alpha") + implementation("com.google.dagger:hilt-android:2.49") + ksp("com.google.dagger:dagger-compiler:2.49") + ksp("com.google.dagger:hilt-compiler:2.49") + // Android Studio Preview support implementation("androidx.compose.ui:ui-tooling-preview") debugImplementation("androidx.compose.ui:ui-tooling") diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml index 274c55e64..facfd24ca 100644 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml @@ -25,7 +25,8 @@ android:label="@string/app_name" android:requestLegacyExternalStorage="true" android:roundIcon="@mipmap/ic_launcher_round" - android:theme="@style/Theme.MPD"> + android:theme="@style/Theme.MPD" + android:name=".MPDApplication"> @@ -53,8 +54,7 @@ + android:name=".Main" /> diff --git a/android/app/src/main/aidl/org/musicpd/IMainCallback.aidl b/android/app/src/main/aidl/org/musicpd/IMainCallback.aidl index c8cdaa4a0..21e435d2a 100644 --- a/android/app/src/main/aidl/org/musicpd/IMainCallback.aidl +++ b/android/app/src/main/aidl/org/musicpd/IMainCallback.aidl @@ -5,5 +5,4 @@ interface IMainCallback void onStarted(); void onStopped(); void onError(String error); - void onLog(int priority, String msg); } diff --git a/android/app/src/main/java/org/musicpd/MPDApplication.kt b/android/app/src/main/java/org/musicpd/MPDApplication.kt new file mode 100644 index 000000000..94d8709cc --- /dev/null +++ b/android/app/src/main/java/org/musicpd/MPDApplication.kt @@ -0,0 +1,9 @@ +package org.musicpd + +import android.app.Application +import dagger.hilt.android.HiltAndroidApp + +@HiltAndroidApp +class MPDApplication : Application() { + +} \ No newline at end of file diff --git a/android/app/src/main/java/org/musicpd/Main.java b/android/app/src/main/java/org/musicpd/Main.java index 7196e0c5f..78bf82fb5 100644 --- a/android/app/src/main/java/org/musicpd/Main.java +++ b/android/app/src/main/java/org/musicpd/Main.java @@ -3,7 +3,6 @@ package org.musicpd; -import android.annotation.TargetApi; import android.app.Notification; import android.app.NotificationManager; import android.app.PendingIntent; @@ -21,15 +20,18 @@ import android.os.PowerManager; import android.os.RemoteCallbackList; import android.os.RemoteException; import android.util.Log; -import android.widget.RemoteViews; - -import androidx.core.app.ServiceCompat; +import org.musicpd.data.LoggingRepository; import org.musicpd.ui.SettingsActivity; import java.lang.reflect.Constructor; import java.lang.reflect.Method; +import javax.inject.Inject; + +import dagger.hilt.android.AndroidEntryPoint; + +@AndroidEntryPoint public class Main extends Service implements Runnable { private static final String TAG = "Main"; private static final String WAKELOCK_TAG = "mpd:wakelockmain"; @@ -39,7 +41,6 @@ public class Main extends Service implements Runnable { private static final int MAIN_STATUS_STARTED = 1; private static final int MSG_SEND_STATUS = 0; - private static final int MSG_SEND_LOG = 1; private Thread mThread = null; private int mStatus = MAIN_STATUS_STOPPED; @@ -50,6 +51,9 @@ public class Main extends Service implements Runnable { private boolean mPauseOnHeadphonesDisconnect = false; private PowerManager.WakeLock mWakelock = null; + @Inject + LoggingRepository logging; + static class MainStub extends IMain.Stub { private Main mService; MainStub(Main service) { @@ -98,9 +102,6 @@ public class Main extends Service implements Runnable { break; } break; - case MSG_SEND_LOG: - cb.onLog(arg1, (String) obj); - break; } } catch (RemoteException e) { } @@ -111,7 +112,7 @@ public class Main extends Service implements Runnable { private Bridge.LogListener mLogListener = new Bridge.LogListener() { @Override public void onLog(int priority, String msg) { - sendMessage(MSG_SEND_LOG, priority, 0, msg); + logging.addLogItem(priority, msg); } }; @@ -303,7 +304,6 @@ public class Main extends Service implements Runnable { public void onStarted(); public void onStopped(); public void onError(String error); - public void onLog(int priority, String msg); } private boolean mBound = false; @@ -327,11 +327,6 @@ public class Main extends Service implements Runnable { public void onError(String error) throws RemoteException { mCallback.onError(error); } - - @Override - public void onLog(int priority, String msg) throws RemoteException { - mCallback.onLog(priority, msg); - } }; private final ServiceConnection mServiceConnection = new ServiceConnection() { diff --git a/android/app/src/main/java/org/musicpd/data/LoggingRepository.kt b/android/app/src/main/java/org/musicpd/data/LoggingRepository.kt new file mode 100644 index 000000000..9e5dd9061 --- /dev/null +++ b/android/app/src/main/java/org/musicpd/data/LoggingRepository.kt @@ -0,0 +1,34 @@ +package org.musicpd.data + +import android.util.Log +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.StateFlow +import javax.inject.Inject +import javax.inject.Singleton + +private const val MAX_LOGS = 500 + +@Singleton +class LoggingRepository @Inject constructor() { + + private val _logItemFLow = MutableStateFlow(listOf()) + val logItemFLow: StateFlow> = _logItemFLow + + fun addLogItem(priority: Int, message: String) { + if (_logItemFLow.value.size > MAX_LOGS) { + _logItemFLow.value = _logItemFLow.value.drop(1) + } + + val priorityString: String = when (priority) { + Log.DEBUG -> "D" + Log.ERROR -> "E" + Log.INFO -> "I" + Log.VERBOSE -> "V" + Log.WARN -> "W" + else -> "" + } + + _logItemFLow.value = _logItemFLow.value + ("$priorityString/$message") + } + +} \ No newline at end of file diff --git a/android/app/src/main/java/org/musicpd/ui/SettingsActivity.kt b/android/app/src/main/java/org/musicpd/ui/SettingsActivity.kt index 56e4b0f92..a36fd57e8 100644 --- a/android/app/src/main/java/org/musicpd/ui/SettingsActivity.kt +++ b/android/app/src/main/java/org/musicpd/ui/SettingsActivity.kt @@ -37,12 +37,14 @@ import com.google.accompanist.permissions.ExperimentalPermissionsApi import com.google.accompanist.permissions.isGranted import com.google.accompanist.permissions.rememberPermissionState import com.google.accompanist.permissions.shouldShowRationale +import dagger.hilt.android.AndroidEntryPoint import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch import org.musicpd.Main import org.musicpd.R +@AndroidEntryPoint class SettingsActivity : ComponentActivity() { private val settingsViewModel: SettingsViewModel by viewModels() @@ -72,10 +74,6 @@ class SettingsActivity : ComponentActivity() { settingsViewModel.updateStatus(error, false) connectClient() } - - override fun onLog(priority: Int, msg: String) { - settingsViewModel.addLogItem(priority, msg) - } }) settingsViewModel.setClient(client) @@ -138,7 +136,7 @@ fun SettingsContainer(settingsViewModel: SettingsViewModel = viewModel()) { settingsViewModel.setPauseOnHeadphonesDisconnect(newValue) } ) - LogView(settingsViewModel.logItemFLow.collectAsStateWithLifecycle()) + LogView(settingsViewModel.getLogs().collectAsStateWithLifecycle()) } } } diff --git a/android/app/src/main/java/org/musicpd/ui/SettingsViewModel.kt b/android/app/src/main/java/org/musicpd/ui/SettingsViewModel.kt index 3d09370ee..6fc2c7002 100644 --- a/android/app/src/main/java/org/musicpd/ui/SettingsViewModel.kt +++ b/android/app/src/main/java/org/musicpd/ui/SettingsViewModel.kt @@ -1,23 +1,23 @@ package org.musicpd.ui import android.content.Context -import android.util.Log import androidx.lifecycle.ViewModel +import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.asStateFlow import org.musicpd.Main import org.musicpd.Preferences +import org.musicpd.data.LoggingRepository +import javax.inject.Inject -private const val MAX_LOGS = 500 - -class SettingsViewModel : ViewModel() { +@HiltViewModel +class SettingsViewModel @Inject constructor( + private var loggingRepository: LoggingRepository +) : ViewModel() { private var mClient: Main.Client? = null - private val _logItemFLow = MutableStateFlow(listOf()) - val logItemFLow: StateFlow> = _logItemFLow - data class StatusUiState( val statusMessage: String = "", val running: Boolean = false @@ -26,21 +26,8 @@ class SettingsViewModel : ViewModel() { private val _statusUIState = MutableStateFlow(StatusUiState()) val statusUIState: StateFlow = _statusUIState.asStateFlow() - fun addLogItem(priority: Int, message: String) { - if (_logItemFLow.value.size > MAX_LOGS) { - _logItemFLow.value = _logItemFLow.value.drop(1) - } - - val priorityString: String = when (priority) { - Log.DEBUG -> "D" - Log.ERROR -> "E" - Log.INFO -> "I" - Log.VERBOSE -> "V" - Log.WARN -> "W" - else -> "" - } - - _logItemFLow.value = _logItemFLow.value + ("$priorityString/$message") + fun getLogs(): StateFlow> { + return loggingRepository.logItemFLow } fun updateStatus(message: String, running: Boolean) { diff --git a/android/build.gradle.kts b/android/build.gradle.kts index 1b4c7195f..32ac8c304 100644 --- a/android/build.gradle.kts +++ b/android/build.gradle.kts @@ -1,5 +1,7 @@ // Top-level build file where you can add configuration options common to all sub-projects/modules. plugins { id("com.android.application") version "8.1.2" apply false - id("org.jetbrains.kotlin.android") version "1.9.20" apply false + id("org.jetbrains.kotlin.android") version "1.9.21" apply false + id("com.google.devtools.ksp") version "1.9.22-1.0.16" apply false + id("com.google.dagger.hilt.android") version "2.49" apply false } \ No newline at end of file