diff --git a/.idea/deploymentTargetDropDown.xml b/.idea/deploymentTargetDropDown.xml
index c822231..da3e07a 100644
--- a/.idea/deploymentTargetDropDown.xml
+++ b/.idea/deploymentTargetDropDown.xml
@@ -16,12 +16,12 @@
-
+
-
+
diff --git a/.idea/kotlinc.xml b/.idea/kotlinc.xml
index fe63bb6..53bf319 100644
--- a/.idea/kotlinc.xml
+++ b/.idea/kotlinc.xml
@@ -1,6 +1,6 @@
-
+
\ No newline at end of file
diff --git a/.idea/misc.xml b/.idea/misc.xml
index 0ad17cb..8978d23 100644
--- a/.idea/misc.xml
+++ b/.idea/misc.xml
@@ -1,4 +1,3 @@
-
diff --git a/app/build.gradle.kts b/app/build.gradle.kts
index b85c705..fc46473 100644
--- a/app/build.gradle.kts
+++ b/app/build.gradle.kts
@@ -1,6 +1,7 @@
plugins {
alias(libs.plugins.androidApplication)
alias(libs.plugins.jetbrainsKotlinAndroid)
+ alias(libs.plugins.compose.compiler)
alias(libs.plugins.googleHilt)
alias(libs.plugins.googleKsp)
alias(libs.plugins.googleGms)
@@ -16,8 +17,8 @@ android {
applicationId = "com.yangdai.opennote"
minSdk = 29
targetSdk = 34
- versionCode = 120
- versionName = "1.2.0"
+ versionCode = 122
+ versionName = "1.2.2"
resourceConfigurations += listOf("en", "zh")
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
@@ -51,8 +52,10 @@ android {
buildFeatures {
compose = true
}
- composeOptions {
- kotlinCompilerExtensionVersion = "1.5.12"
+ composeCompiler {
+ enableStrongSkippingMode = true
+ enableIntrinsicRemember = true
+ enableNonSkippingGroupOptimization = true
}
packaging {
resources {
@@ -95,11 +98,10 @@ dependencies {
annotationProcessor(libs.androidx.room.compiler)
ksp(libs.androidx.room.compiler)
implementation(libs.androidx.room.ktx)
- implementation(libs.androidx.room.paging)
testImplementation(libs.androidx.room.testing)
// Hilt, for dependency injection
- implementation(libs.androidx.hilt)
+ implementation(libs.androidx.hilt.navigation)
ksp(libs.google.hilt.compiler)
implementation(libs.google.hilt)
@@ -124,7 +126,6 @@ dependencies {
implementation(libs.androidx.core.splashscreen)
implementation(libs.androidx.biometric)
implementation(libs.androidx.datastore.preferences)
- implementation(libs.androidx.core.ktx)
implementation(libs.androidx.appcompat)
// Test
diff --git a/app/release/app-release.apk b/app/release/app-release.apk
index 16aea74..9203e94 100644
Binary files a/app/release/app-release.apk and b/app/release/app-release.apk differ
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index a786dd7..d3f451d 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -4,15 +4,11 @@
-
+
-
-
@@ -36,15 +32,15 @@
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:localeConfig="@xml/locales_config"
+ android:requestLegacyExternalStorage="true"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
- android:theme="@style/Theme.OpenNote"
+ android:theme="@style/Theme.OpenNote.Starting"
android:usesCleartextTraffic="true"
tools:targetApi="tiramisu">
diff --git a/app/src/main/java/com/yangdai/opennote/MainActivity.kt b/app/src/main/java/com/yangdai/opennote/MainActivity.kt
index f702f71..076bde4 100644
--- a/app/src/main/java/com/yangdai/opennote/MainActivity.kt
+++ b/app/src/main/java/com/yangdai/opennote/MainActivity.kt
@@ -43,7 +43,7 @@ class MainActivity : AppCompatActivity() {
0f
)
- animation.duration = 200L
+ animation.duration = 300L
// Call SplashScreenView.remove at the end of your custom animation.
animation.doOnEnd { splashScreenView.remove() }
@@ -54,7 +54,6 @@ class MainActivity : AppCompatActivity() {
}
enableEdgeToEdge()
-
super.onCreate(savedInstanceState)
setContent {
diff --git a/app/src/main/java/com/yangdai/opennote/data/repository/DataStoreRepositoryImpl.kt b/app/src/main/java/com/yangdai/opennote/data/repository/DataStoreRepositoryImpl.kt
index 328f647..01b651c 100644
--- a/app/src/main/java/com/yangdai/opennote/data/repository/DataStoreRepositoryImpl.kt
+++ b/app/src/main/java/com/yangdai/opennote/data/repository/DataStoreRepositoryImpl.kt
@@ -5,6 +5,7 @@ import androidx.datastore.core.DataStore
import androidx.datastore.preferences.core.Preferences
import androidx.datastore.preferences.core.booleanPreferencesKey
import androidx.datastore.preferences.core.edit
+import androidx.datastore.preferences.core.floatPreferencesKey
import androidx.datastore.preferences.core.intPreferencesKey
import androidx.datastore.preferences.core.stringPreferencesKey
import androidx.datastore.preferences.core.stringSetPreferencesKey
@@ -38,6 +39,13 @@ class DataStoreRepositoryImpl @Inject constructor(
}
}
+ override suspend fun putFloat(key: String, value: Float) {
+ val preferencesKey = floatPreferencesKey(key)
+ context.dataStore.edit { preferences ->
+ preferences[preferencesKey] = value
+ }
+ }
+
override suspend fun putBoolean(key: String, value: Boolean) {
val preferencesKey = booleanPreferencesKey(key)
context.dataStore.edit { preferences ->
@@ -67,6 +75,17 @@ class DataStoreRepositoryImpl @Inject constructor(
}
}
+ override suspend fun getFloat(key: String): Float? {
+ return try {
+ val preferencesKey = floatPreferencesKey(key)
+ val preferences = context.dataStore.data.first()
+ preferences[preferencesKey]
+ } catch (e: Exception) {
+ e.printStackTrace()
+ null
+ }
+ }
+
override suspend fun getBoolean(key: String): Boolean? {
return try {
val preferencesKey = booleanPreferencesKey(key)
@@ -103,6 +122,13 @@ class DataStoreRepositoryImpl @Inject constructor(
}
}
+ override fun floatFlow(key: String): Flow {
+ val preferencesKey = floatPreferencesKey(key)
+ return context.dataStore.data.map { preferences ->
+ preferences[preferencesKey] ?: 0f
+ }
+ }
+
override fun stringFlow(key: String): Flow {
val preferencesKey = stringPreferencesKey(key)
return context.dataStore.data.map { preferences ->
@@ -123,12 +149,4 @@ class DataStoreRepositoryImpl @Inject constructor(
preferences[preferencesKey] ?: setOf()
}
}
-
- override fun preferencesFlow(): Flow {
- return context.dataStore.data
- }
-
- override fun getDataStore(): DataStore {
- return context.dataStore
- }
}
diff --git a/app/src/main/java/com/yangdai/opennote/domain/repository/DataStoreRepository.kt b/app/src/main/java/com/yangdai/opennote/domain/repository/DataStoreRepository.kt
index 4c2537c..18ba4cf 100644
--- a/app/src/main/java/com/yangdai/opennote/domain/repository/DataStoreRepository.kt
+++ b/app/src/main/java/com/yangdai/opennote/domain/repository/DataStoreRepository.kt
@@ -1,24 +1,24 @@
package com.yangdai.opennote.domain.repository
-import androidx.datastore.core.DataStore
-import androidx.datastore.preferences.core.Preferences
import kotlinx.coroutines.flow.Flow
interface DataStoreRepository {
suspend fun putString(key: String, value: String)
suspend fun putInt(key: String, value: Int)
+ suspend fun putFloat(key: String, value: Float)
+ suspend fun putBoolean(key: String, value: Boolean)
+ suspend fun putStringSet(key: String, value: Set)
+
suspend fun getString(key: String): String?
suspend fun getInt(key: String): Int?
- suspend fun putBoolean(key: String, value: Boolean)
+ suspend fun getFloat(key: String): Float?
suspend fun getBoolean(key: String): Boolean?
- suspend fun putStringSet(key: String, value: Set)
suspend fun getStringSet(key: String): Set?
fun intFlow(key: String): Flow
+ fun floatFlow(key: String): Flow
fun stringFlow(key: String): Flow
fun booleanFlow(key: String): Flow
fun stringSetFlow(key: String): Flow>
- fun preferencesFlow(): Flow
- fun getDataStore(): DataStore
}
\ No newline at end of file
diff --git a/app/src/main/java/com/yangdai/opennote/presentation/component/CurlyCornerShape.kt b/app/src/main/java/com/yangdai/opennote/presentation/component/CurlyCornerShape.kt
index ba8f852..b405cea 100644
--- a/app/src/main/java/com/yangdai/opennote/presentation/component/CurlyCornerShape.kt
+++ b/app/src/main/java/com/yangdai/opennote/presentation/component/CurlyCornerShape.kt
@@ -41,7 +41,7 @@ class CurlyCornerShape(
topEnd: Float,
bottomEnd: Float,
bottomStart: Float,
- layoutDirection: LayoutDirection,
+ layoutDirection: LayoutDirection
): Outline {
val d = 2.0
val r2: Double = size.width / d
diff --git a/app/src/main/java/com/yangdai/opennote/presentation/component/MarkdownText.kt b/app/src/main/java/com/yangdai/opennote/presentation/component/MarkdownText.kt
index 4dc3bee..0c4ce52 100644
--- a/app/src/main/java/com/yangdai/opennote/presentation/component/MarkdownText.kt
+++ b/app/src/main/java/com/yangdai/opennote/presentation/component/MarkdownText.kt
@@ -73,7 +73,8 @@ fun MarkdownText(html: String) {
setPadding(0, 0, 0, 0)
setBackgroundColor(Color.TRANSPARENT)
}
- }, update = {
+ },
+ update = {
val data = """
diff --git a/app/src/main/java/com/yangdai/opennote/presentation/component/SelectableColorPlatte.kt b/app/src/main/java/com/yangdai/opennote/presentation/component/SelectableColorPlatte.kt
index 2a9dfab..ebbfa63 100644
--- a/app/src/main/java/com/yangdai/opennote/presentation/component/SelectableColorPlatte.kt
+++ b/app/src/main/java/com/yangdai/opennote/presentation/component/SelectableColorPlatte.kt
@@ -62,7 +62,7 @@ fun SelectableColorPlatte(
modifier = Modifier
.align(Alignment.Center)
.clip(CircleShape)
- .background(MaterialTheme.colorScheme.primary),
+ .background(colorScheme.tertiaryContainer),
enter = fadeIn() + expandIn(expandFrom = Alignment.Center),
exit = shrinkOut(shrinkTowards = Alignment.Center) + fadeOut()
) {
diff --git a/app/src/main/java/com/yangdai/opennote/presentation/component/SettingsDetailPane.kt b/app/src/main/java/com/yangdai/opennote/presentation/component/SettingsDetailPane.kt
index 0fff97e..d9c1842 100644
--- a/app/src/main/java/com/yangdai/opennote/presentation/component/SettingsDetailPane.kt
+++ b/app/src/main/java/com/yangdai/opennote/presentation/component/SettingsDetailPane.kt
@@ -1,11 +1,8 @@
package com.yangdai.opennote.presentation.component
-import android.Manifest
-import android.app.Activity
import android.app.KeyguardManager
import android.content.Context
import android.content.Intent
-import android.content.pm.PackageManager
import android.net.Uri
import android.os.Build
import android.widget.Toast
@@ -69,12 +66,11 @@ import androidx.compose.material3.TextButton
import androidx.compose.material3.TopAppBarDefaults
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
-import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
+import androidx.compose.runtime.mutableFloatStateOf
import androidx.compose.runtime.mutableIntStateOf
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
-import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
@@ -91,11 +87,6 @@ import androidx.compose.ui.res.stringResource
import androidx.compose.ui.semantics.Role
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.dp
-import androidx.core.app.ActivityCompat
-import androidx.core.content.ContextCompat
-import androidx.datastore.preferences.core.booleanPreferencesKey
-import androidx.datastore.preferences.core.edit
-import androidx.datastore.preferences.core.floatPreferencesKey
import androidx.hilt.navigation.compose.hiltViewModel
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.google.firebase.analytics.FirebaseAnalytics
@@ -110,8 +101,6 @@ import com.yangdai.opennote.presentation.theme.DarkPurpleColors
import com.yangdai.opennote.presentation.util.Constants
import com.yangdai.opennote.presentation.viewmodel.SharedViewModel
import kotlinx.collections.immutable.toImmutableList
-import kotlinx.coroutines.flow.map
-import kotlinx.coroutines.launch
@OptIn(ExperimentalMaterial3Api::class)
@Composable
@@ -123,7 +112,8 @@ fun SettingsDetailPane(
val context = LocalContext.current
val haptic = LocalHapticFeedback.current
- val scope = rememberCoroutineScope()
+ val settingsState by sharedViewModel.settingsStateFlow.collectAsStateWithLifecycle()
+
val customTabsIntent = CustomTabsIntent.Builder()
.setShowTitle(true)
.build()
@@ -165,22 +155,8 @@ fun SettingsDetailPane(
mutableStateOf(initFirebaseSelect)
}
- val isAppInDarkTheme by sharedViewModel.preferencesFlow()
- .map { preferences ->
- preferences[booleanPreferencesKey(Constants.Preferences.IS_APP_IN_DARK_MODE)] ?: false
- }
- .collectAsState(initial = false)
-
fun switchTheme() {
- scope.launch {
- sharedViewModel
- .getDataStore()
- .edit {
- it[floatPreferencesKey(Constants.Preferences.MASK_CLICK_X)] = 0f
- it[floatPreferencesKey(Constants.Preferences.MASK_CLICK_Y)] = 0f
- it[booleanPreferencesKey(Constants.Preferences.IS_SWITCH_ACTIVE)] = true
- }
- }
+ sharedViewModel.putPreferenceValue(Constants.Preferences.IS_SWITCH_ACTIVE, true)
}
val isSystemDarkTheme = isSystemInDarkTheme()
@@ -329,7 +305,7 @@ fun SettingsDetailPane(
if (mode != index) {
when (index) {
0 -> {
- if (isSystemDarkTheme != isAppInDarkTheme) {
+ if (isSystemDarkTheme != settingsState.isAppInDarkMode) {
switchTheme()
} else {
sharedViewModel.putPreferenceValue(
@@ -344,7 +320,7 @@ fun SettingsDetailPane(
}
1 -> {
- if (isAppInDarkTheme) {
+ if (settingsState.isAppInDarkMode) {
switchTheme()
}
sharedViewModel.putPreferenceValue(
@@ -358,7 +334,7 @@ fun SettingsDetailPane(
}
2 -> {
- if (!isAppInDarkTheme) {
+ if (!settingsState.isAppInDarkMode) {
switchTheme()
}
sharedViewModel.putPreferenceValue(
@@ -419,13 +395,7 @@ fun SettingsDetailPane(
ListItem(
modifier = Modifier.clickable {
- if (!hasStoragePermissions(context)) {
- ActivityCompat.requestPermissions(
- context as Activity, STORAGE_PERMISSIONS, 0
- )
- } else {
- showFolderDialog = true
- }
+ showFolderDialog = true
},
leadingContent = {
Icon(
@@ -559,7 +529,7 @@ fun SettingsDetailPane(
0
)
val version = packageInfo.versionName
- var pressAMP by remember { mutableStateOf(16f) }
+ var pressAMP by remember { mutableFloatStateOf(16f) }
val animatedPress by animateFloatAsState(
targetValue = pressAMP,
animationSpec = tween(), label = ""
@@ -567,18 +537,7 @@ fun SettingsDetailPane(
Column(
modifier = Modifier
.fillMaxWidth()
- .padding(vertical = 16.dp)
- .pointerInput(Unit) {
- detectTapGestures(
- onPress = {
- haptic.performHapticFeedback(HapticFeedbackType.LongPress)
- pressAMP = 0f
- tryAwaitRelease()
- haptic.performHapticFeedback(HapticFeedbackType.LongPress)
- pressAMP = 16f
- }
- )
- },
+ .padding(vertical = 16.dp),
verticalArrangement = Arrangement.Center,
horizontalAlignment = Alignment.CenterHorizontally
) {
@@ -594,7 +553,18 @@ fun SettingsDetailPane(
shape = CurlyCornerShape(amp = animatedPress.toDouble()),
ambientColor = MaterialTheme.colorScheme.primaryContainer,
spotColor = MaterialTheme.colorScheme.primaryContainer,
- ),
+ )
+ .pointerInput(Unit) {
+ detectTapGestures(
+ onPress = {
+ haptic.performHapticFeedback(HapticFeedbackType.LongPress)
+ pressAMP = 0f
+ tryAwaitRelease()
+ haptic.performHapticFeedback(HapticFeedbackType.LongPress)
+ pressAMP = 16f
+ }
+ )
+ },
contentAlignment = Alignment.Center,
) {
Image(
@@ -783,21 +753,6 @@ fun SettingsDetailPane(
}
}
-fun hasStoragePermissions(
- context: Context
-): Boolean {
- if (Build.VERSION.SDK_INT > Build.VERSION_CODES.S) {
- return true
- }
- return STORAGE_PERMISSIONS.all {
- ContextCompat.checkSelfPermission(context, it) == PackageManager.PERMISSION_GRANTED
- }
-}
-
-val STORAGE_PERMISSIONS = arrayOf(
- Manifest.permission.READ_EXTERNAL_STORAGE
-)
-
@Composable
fun SettingsDetailPlaceHolder() =
Column(horizontalAlignment = Alignment.CenterHorizontally) {
diff --git a/app/src/main/java/com/yangdai/opennote/presentation/navigation/AnimatedNavHost.kt b/app/src/main/java/com/yangdai/opennote/presentation/navigation/AnimatedNavHost.kt
index 9730bac..23a3f27 100644
--- a/app/src/main/java/com/yangdai/opennote/presentation/navigation/AnimatedNavHost.kt
+++ b/app/src/main/java/com/yangdai/opennote/presentation/navigation/AnimatedNavHost.kt
@@ -22,7 +22,7 @@ import com.yangdai.opennote.presentation.screen.SettingsScreen
import com.yangdai.opennote.presentation.util.Constants.NAV_ANIMATION_TIME
import com.yangdai.opennote.presentation.util.parseSharedContent
-private fun sharedAxisXIn(
+fun sharedAxisXIn(
initialOffsetX: (fullWidth: Int) -> Int,
durationMillis: Int = NAV_ANIMATION_TIME,
): EnterTransition = slideInHorizontally(
@@ -33,7 +33,7 @@ private fun sharedAxisXIn(
initialOffsetX = initialOffsetX
)
-private fun sharedAxisXOut(
+fun sharedAxisXOut(
targetOffsetX: (fullWidth: Int) -> Int,
durationMillis: Int = NAV_ANIMATION_TIME,
): ExitTransition = slideOutHorizontally(
diff --git a/app/src/main/java/com/yangdai/opennote/presentation/screen/BaseScreen.kt b/app/src/main/java/com/yangdai/opennote/presentation/screen/BaseScreen.kt
index 3f3e6a7..571ba30 100644
--- a/app/src/main/java/com/yangdai/opennote/presentation/screen/BaseScreen.kt
+++ b/app/src/main/java/com/yangdai/opennote/presentation/screen/BaseScreen.kt
@@ -8,7 +8,6 @@ import androidx.compose.foundation.isSystemInDarkTheme
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
-import androidx.compose.runtime.State
import androidx.compose.runtime.derivedStateOf
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
@@ -19,9 +18,6 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.blur
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.unit.dp
-import androidx.datastore.preferences.core.Preferences
-import androidx.datastore.preferences.core.booleanPreferencesKey
-import androidx.datastore.preferences.core.floatPreferencesKey
import androidx.hilt.navigation.compose.hiltViewModel
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import androidx.navigation.compose.rememberNavController
@@ -32,7 +28,6 @@ import com.yangdai.opennote.presentation.component.MaskBox
import com.yangdai.opennote.presentation.navigation.AnimatedNavHost
import com.yangdai.opennote.presentation.theme.OpenNoteTheme
import com.yangdai.opennote.presentation.util.Constants
-import kotlinx.coroutines.flow.map
@Composable
fun BaseScreen(
@@ -54,32 +49,6 @@ fun BaseScreen(
}
}
- val isAppInDarkTheme by getPreferenceState(
- sharedViewModel,
- booleanPreferencesKey(Constants.Preferences.IS_APP_IN_DARK_MODE),
- false
- )
- val shouldFollowSystem by getPreferenceState(
- sharedViewModel,
- booleanPreferencesKey(Constants.Preferences.SHOULD_FOLLOW_SYSTEM),
- false
- )
- val switchActive by getPreferenceState(
- sharedViewModel,
- booleanPreferencesKey(Constants.Preferences.IS_SWITCH_ACTIVE),
- false
- )
- val maskClickX by getPreferenceState(
- sharedViewModel,
- floatPreferencesKey(Constants.Preferences.MASK_CLICK_X),
- 0f
- )
- val maskClickY by getPreferenceState(
- sharedViewModel,
- floatPreferencesKey(Constants.Preferences.MASK_CLICK_Y),
- 0f
- )
-
val isSystemInDarkTheme = isSystemInDarkTheme()
LaunchedEffect(settingsState.theme) {
@@ -90,29 +59,29 @@ fun BaseScreen(
OpenNoteTheme(
color = settingsState.color,
- darkMode = isAppInDarkTheme
+ darkMode = settingsState.isAppInDarkMode
) {
// MaskBox is a custom composable that animates a mask over the screen
MaskBox(
maskComplete = {
- sharedViewModel.putPreferenceValue(Constants.Preferences.IS_APP_IN_DARK_MODE, !isAppInDarkTheme)
+ sharedViewModel.putPreferenceValue(Constants.Preferences.IS_APP_IN_DARK_MODE, !settingsState.isAppInDarkMode)
},
animFinish = {
sharedViewModel.putPreferenceValue(Constants.Preferences.IS_SWITCH_ACTIVE, false)
- if (shouldFollowSystem) {
+ if (settingsState.shouldFollowSystem) {
sharedViewModel.putPreferenceValue(Constants.Preferences.APP_THEME, 0)
}
}
) { maskActiveEvent ->
- LaunchedEffect(switchActive) {
- if (!switchActive) return@LaunchedEffect
+ LaunchedEffect(settingsState.isSwitchActive) {
+ if (!settingsState.isSwitchActive) return@LaunchedEffect
- if (isAppInDarkTheme)
- maskActiveEvent(MaskAnimModel.SHRINK, maskClickX, maskClickY)
+ if (settingsState.isAppInDarkMode)
+ maskActiveEvent(MaskAnimModel.SHRINK, Constants.Preferences.MASK_CLICK_X, Constants.Preferences.MASK_CLICK_Y)
else
- maskActiveEvent(MaskAnimModel.EXPEND, maskClickX, maskClickY)
+ maskActiveEvent(MaskAnimModel.EXPEND, Constants.Preferences.MASK_CLICK_X, Constants.Preferences.MASK_CLICK_Y)
}
val blur by animateDpAsState(targetValue = if (!loggedIn) 16.dp else 0.dp, label = "")
@@ -138,14 +107,3 @@ fun BaseScreen(
}
}
}
-
-@Composable
-private fun getPreferenceState(
- viewModel: SharedViewModel,
- key: Preferences.Key,
- defaultValue: T
-): State {
- return viewModel.preferencesFlow()
- .map { preferences -> preferences[key] ?: defaultValue }
- .collectAsStateWithLifecycle(initialValue = defaultValue)
-}
diff --git a/app/src/main/java/com/yangdai/opennote/presentation/state/SettingsState.kt b/app/src/main/java/com/yangdai/opennote/presentation/state/SettingsState.kt
index a1831ca..961af8c 100644
--- a/app/src/main/java/com/yangdai/opennote/presentation/state/SettingsState.kt
+++ b/app/src/main/java/com/yangdai/opennote/presentation/state/SettingsState.kt
@@ -3,5 +3,8 @@ package com.yangdai.opennote.presentation.state
data class SettingsState(
val theme: Int = -1,
val color: Int = 0,
- val needPassword: Boolean = false
+ val needPassword: Boolean = false,
+ val isAppInDarkMode: Boolean = false,
+ val shouldFollowSystem: Boolean = false,
+ val isSwitchActive: Boolean = false
)
diff --git a/app/src/main/java/com/yangdai/opennote/presentation/theme/Theme.kt b/app/src/main/java/com/yangdai/opennote/presentation/theme/Theme.kt
index e466fdd..41e2f34 100644
--- a/app/src/main/java/com/yangdai/opennote/presentation/theme/Theme.kt
+++ b/app/src/main/java/com/yangdai/opennote/presentation/theme/Theme.kt
@@ -8,8 +8,6 @@ import androidx.compose.material3.dynamicDarkColorScheme
import androidx.compose.material3.dynamicLightColorScheme
import androidx.compose.runtime.Composable
import androidx.compose.runtime.SideEffect
-import androidx.compose.ui.graphics.Color
-import androidx.compose.ui.graphics.toArgb
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.LocalView
import androidx.core.view.WindowCompat
@@ -36,20 +34,10 @@ fun OpenNoteTheme(
}
}
-// val colorScheme = when {
-// dynamicColor && Build.VERSION.SDK_INT >= Build.VERSION_CODES.S -> {
-// val context = LocalContext.current
-// if (darkTheme) dynamicDarkColorScheme(context) else dynamicLightColorScheme(context)
-// }
-//
-// darkTheme -> DarkPurpleColors
-// else -> LightPurpleColors
-// }
val view = LocalView.current
if (!view.isInEditMode) {
SideEffect {
val window = (view.context as Activity).window
- window.statusBarColor = Color.Transparent.toArgb()
WindowCompat.getInsetsController(window, view).isAppearanceLightStatusBars = !darkMode
}
}
diff --git a/app/src/main/java/com/yangdai/opennote/presentation/util/Constants.kt b/app/src/main/java/com/yangdai/opennote/presentation/util/Constants.kt
index d2a740e..9afe769 100644
--- a/app/src/main/java/com/yangdai/opennote/presentation/util/Constants.kt
+++ b/app/src/main/java/com/yangdai/opennote/presentation/util/Constants.kt
@@ -7,7 +7,6 @@ object Constants {
object File {
const val OPENNOTE = "OpenNote"
- const val BACKUP = "Backup"
const val OPENNOTE_BACKUP = "OpenNote/Backup"
}
@@ -20,8 +19,8 @@ object Constants {
const val IS_APP_IN_DARK_MODE = "IS_APP_IN_DARK_MODE"
const val SHOULD_FOLLOW_SYSTEM = "SHOULD_FOLLOW_SYSTEM"
const val IS_SWITCH_ACTIVE = "IS_DARK_SWITCH_ACTIVE"
- const val MASK_CLICK_X = "MASK_CLICK_X"
- const val MASK_CLICK_Y = "MASK_CLICK_Y"
+ const val MASK_CLICK_X = 0f
+ const val MASK_CLICK_Y = 0f
}
object Editor {
diff --git a/app/src/main/java/com/yangdai/opennote/presentation/util/Utils.kt b/app/src/main/java/com/yangdai/opennote/presentation/util/Utils.kt
index d3db485..760e2b5 100644
--- a/app/src/main/java/com/yangdai/opennote/presentation/util/Utils.kt
+++ b/app/src/main/java/com/yangdai/opennote/presentation/util/Utils.kt
@@ -2,8 +2,6 @@ package com.yangdai.opennote.presentation.util
import android.content.Intent
import android.icu.text.DateFormat
-import android.os.Environment
-import java.io.File
import java.util.Date
fun Intent.isTextMimeType() = type?.startsWith(Constants.MIME_TYPE_TEXT) == true
@@ -22,25 +20,3 @@ fun Long.timestampToFormatLocalDateTime(): String {
return DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.SHORT)
.format(Date(this))
}
-
-fun createAppDirectory(): String {
- val directory = File(
- Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS),
- Constants.File.OPENNOTE
- )
- if (!directory.exists()) {
- directory.mkdirs()
- }
- return directory.absolutePath
-}
-
-fun createBackupDirectory(): String {
- val directory = File(
- Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS),
- Constants.File.OPENNOTE_BACKUP
- )
- if (!directory.exists()) {
- directory.mkdirs()
- }
- return directory.absolutePath
-}
\ No newline at end of file
diff --git a/app/src/main/java/com/yangdai/opennote/presentation/viewmodel/SharedViewModel.kt b/app/src/main/java/com/yangdai/opennote/presentation/viewmodel/SharedViewModel.kt
index c3e7f90..6dd7f80 100644
--- a/app/src/main/java/com/yangdai/opennote/presentation/viewmodel/SharedViewModel.kt
+++ b/app/src/main/java/com/yangdai/opennote/presentation/viewmodel/SharedViewModel.kt
@@ -12,7 +12,6 @@ import androidx.compose.foundation.text.input.TextFieldState
import androidx.compose.foundation.text.input.clearText
import androidx.compose.foundation.text.input.setTextAndPlaceCursorAtEnd
import androidx.compose.runtime.snapshotFlow
-import androidx.datastore.preferences.core.Preferences
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.google.gson.Gson
@@ -41,9 +40,7 @@ import com.yangdai.opennote.presentation.util.add
import com.yangdai.opennote.presentation.util.addLink
import com.yangdai.opennote.presentation.util.addTask
import com.yangdai.opennote.presentation.util.bold
-import com.yangdai.opennote.presentation.util.createBackupDirectory
import com.yangdai.opennote.presentation.util.diagram
-import com.yangdai.opennote.presentation.util.createAppDirectory
import com.yangdai.opennote.presentation.util.inlineCode
import com.yangdai.opennote.presentation.util.inlineFunction
import com.yangdai.opennote.presentation.util.italic
@@ -57,7 +54,6 @@ import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.FlowPreview
import kotlinx.coroutines.Job
import kotlinx.coroutines.delay
-import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.SharingStarted
@@ -158,7 +154,7 @@ class SharedViewModel @Inject constructor(
} else {
TextRecognition.getClient(TextRecognizerOptions.DEFAULT_OPTIONS)
}
- delay(500)
+ delay(300)
//任务完成后将 isLoading 设置为 false 以隐藏启动屏幕
_isLoadingData.value = false
}
@@ -170,11 +166,17 @@ class SharedViewModel @Inject constructor(
dataStoreRepository.intFlow(Constants.Preferences.APP_THEME),
dataStoreRepository.intFlow(Constants.Preferences.APP_COLOR),
dataStoreRepository.booleanFlow(Constants.Preferences.NEED_PASSWORD),
- ) { theme, color, needPassword ->
+ dataStoreRepository.booleanFlow(Constants.Preferences.IS_APP_IN_DARK_MODE),
+ dataStoreRepository.booleanFlow(Constants.Preferences.SHOULD_FOLLOW_SYSTEM),
+ dataStoreRepository.booleanFlow(Constants.Preferences.IS_SWITCH_ACTIVE)
+ ) { values ->
SettingsState(
- theme = theme,
- color = color,
- needPassword = needPassword
+ theme = values[0] as Int,
+ color = values[1] as Int,
+ needPassword = values[2] as Boolean,
+ isAppInDarkMode = values[3] as Boolean,
+ shouldFollowSystem = values[4] as Boolean,
+ isSwitchActive = values[5] as Boolean
)
}.flowOn(Dispatchers.IO).stateIn(
scope = viewModelScope,
@@ -182,10 +184,6 @@ class SharedViewModel @Inject constructor(
initialValue = SettingsState()
)
- fun preferencesFlow(): Flow {
- return dataStoreRepository.preferencesFlow()
- }
-
fun putPreferenceValue(key: String, value: T) {
viewModelScope.launch(Dispatchers.IO) {
when (value) {
@@ -210,9 +208,6 @@ class SharedViewModel @Inject constructor(
dataStoreRepository.getBoolean(key)
}
- fun getDataStore() = dataStoreRepository.getDataStore()
-
-
val historyStateFlow: StateFlow> =
dataStoreRepository.stringSetFlow(Constants.Preferences.SEARCH_HISTORY)
.stateIn(
@@ -499,9 +494,9 @@ class SharedViewModel @Inject constructor(
fun getFileName(contentResolver: ContentResolver, uri: Uri): String? {
var result: String? = null
if (uri.scheme == "content") {
- val cursor = contentResolver.query(uri, null, null, null, null)
- cursor.use {
- if (it != null && it.moveToFirst()) {
+ val cursor = contentResolver.query(uri, null, null, null, null, null)
+ cursor?.use {
+ if (it.moveToFirst()) {
result = it.getString(it.getColumnIndex(OpenableColumns.DISPLAY_NAME))
}
}
@@ -573,8 +568,6 @@ class SharedViewModel @Inject constructor(
else -> ".html"
}
- createAppDirectory()
-
dataActionJob = viewModelScope.launch(Dispatchers.IO) {
notes.forEachIndexed { index, noteEntity ->
_dataActionState.update {
@@ -627,7 +620,6 @@ class SharedViewModel @Inject constructor(
dataActionJob?.cancel()
_dataActionState.update { it.copy(loading = true) }
- createBackupDirectory()
_dataActionState.update {
it.copy(progress = 0.2f)
}
diff --git a/app/src/main/res/values-zh/strings.xml b/app/src/main/res/values-zh/strings.xml
index 3be6915..a4c5dc7 100644
--- a/app/src/main/res/values-zh/strings.xml
+++ b/app/src/main/res/values-zh/strings.xml
@@ -30,7 +30,6 @@
登录
数据和安全
重置数据库
- 请重启应用
提醒
全部恢复
全部删除
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index d550724..a8312db 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -30,7 +30,6 @@
Login
Data and security
Reset database
- Please relaunch the app
Welcome to \"Open Note\", a lightweight, aesthetically pleasing application that adheres to the Material 3 design style. Our app offers local storage, allowing you to jot down your thoughts anytime, anywhere, even without an internet connection. The efficient search function helps you quickly locate your notes, while the folder categorization feature aids in better organization of your notes. Additionally, it provides a text OCR feature, capable of converting text in images into editable text. The goal is to provide you with the most convenient and efficient note-taking experience. Download: https://play.google.com/store/apps/details?id=com.yangdai.opennote
Remind
All restore
diff --git a/app/src/main/res/values/themes.xml b/app/src/main/res/values/themes.xml
index 5605d7c..2d1351b 100644
--- a/app/src/main/res/values/themes.xml
+++ b/app/src/main/res/values/themes.xml
@@ -2,9 +2,7 @@
diff --git a/build.gradle.kts b/build.gradle.kts
index 5ec66aa..d95a47e 100644
--- a/build.gradle.kts
+++ b/build.gradle.kts
@@ -2,6 +2,7 @@
plugins {
alias(libs.plugins.androidApplication) apply false
alias(libs.plugins.jetbrainsKotlinAndroid) apply false
+ alias(libs.plugins.compose.compiler) apply false
alias(libs.plugins.googleHilt) apply false
alias(libs.plugins.googleKsp) apply false
alias(libs.plugins.googleGms) apply false
diff --git a/gradle.properties b/gradle.properties
index 20e2a01..126cd0f 100644
--- a/gradle.properties
+++ b/gradle.properties
@@ -20,4 +20,5 @@ kotlin.code.style=official
# Enables namespacing of each library's R class so that its R class includes only the
# resources declared in the library itself and none from the library's dependencies,
# thereby reducing the size of the R class for that library
-android.nonTransitiveRClass=true
\ No newline at end of file
+android.nonTransitiveRClass=true
+kotlin.native.disableCompilerDaemon = true
\ No newline at end of file
diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml
index 4323681..b7446f5 100644
--- a/gradle/libs.versions.toml
+++ b/gradle/libs.versions.toml
@@ -1,34 +1,33 @@
[versions]
-agp = "8.3.2"
+agp = "8.4.0"
browser = "1.8.0"
cameraCore = "1.3.3"
commonmark = "0.22.0"
-coreSplashscreen = "1.0.1"
-datastorePreferences = "1.1.0"
+datastorePreferences = "1.1.1"
firebaseBom = "32.8.1"
-kotlin = "1.9.23"
-coreKtx = "1.13.0"
+kotlin = "2.0.0-RC2"
junit = "4.13.2"
junitVersion = "1.1.5"
espressoCore = "3.5.1"
kotlinxCollectionsImmutable = "0.3.7"
activityCompose = "1.9.0"
-composeBom = "2024.04.01"
+composeBom = "2024.05.00"
appcompat = "1.6.1"
hilt = "2.51.1"
hiltNav = "1.2.0"
room = "2.6.1"
-ksp = "1.9.23-1.0.20"
lifecycleRuntimeCompose = "2.7.0"
gms = "4.4.1"
textRecognition = "16.0.0"
firebase-crashlytics = "2.9.9"
gson = "2.10.1"
+coreSplashscreen = "1.2.0-alpha01"
+ksp = "2.0.0-RC2-1.0.20"
biometricVersion = "1.2.0-alpha05"
-navVersion = "2.8.0-alpha07"
-foundation = "1.7.0-alpha07"
-m3 = "1.3.0-alpha05"
-adaptiveVersion = "1.0.0-alpha11"
+navVersion = "2.8.0-alpha08"
+foundation = "1.7.0-alpha08"
+m3 = "1.3.0-alpha06"
+adaptiveVersion = "1.0.0-alpha12"
[libraries]
@@ -38,7 +37,6 @@ androidx-camera-lifecycle = { group = "androidx.camera", name = "camera-lifecycl
androidx-camera-view = { group = "androidx.camera", name = "camera-view", version.ref = "cameraCore" }
androidx-appcompat = { group = "androidx.appcompat", name = "appcompat", version.ref = "appcompat" }
-androidx-core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "coreKtx" }
androidx-core-splashscreen = { group = "androidx.core", name = "core-splashscreen", version.ref = "coreSplashscreen" }
androidx-datastore-preferences = { group = "androidx.datastore", name = "datastore-preferences", version.ref = "datastorePreferences" }
androidx-biometric = { group = "androidx.biometric", name = "biometric-ktx", version.ref = "biometricVersion" }
@@ -78,12 +76,11 @@ androidx-navigation-compose = { group = "androidx.navigation", name = "navigatio
google-hilt = { group = "com.google.dagger", name = "hilt-android", version.ref = "hilt" }
google-hilt-compiler = { group = "com.google.dagger", name = "hilt-android-compiler", version.ref = "hilt" }
-androidx-hilt = { group = "androidx.hilt", name = "hilt-navigation-compose", version.ref = "hiltNav" }
+androidx-hilt-navigation = { group = "androidx.hilt", name = "hilt-navigation-compose", version.ref = "hiltNav" }
androidx-room-runtime = { group = "androidx.room", name = "room-runtime", version.ref = "room" }
androidx-room-compiler = { group = "androidx.room", name = "room-compiler", version.ref = "room" }
androidx-room-ktx = { group = "androidx.room", name = "room-ktx", version.ref = "room" }
-androidx-room-paging = { group = "androidx.room", name = "room-paging", version.ref = "room" }
androidx-room-testing = { group = "androidx.room", name = "room-testing", version.ref = "room" }
google-gson = { group = "com.google.code.gson", name = "gson", version.ref = "gson" }
@@ -94,6 +91,7 @@ text-recognition-chinese = { group = "com.google.mlkit", name = "text-recognitio
[plugins]
androidApplication = { id = "com.android.application", version.ref = "agp" }
jetbrainsKotlinAndroid = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" }
+compose-compiler = { id = "org.jetbrains.kotlin.plugin.compose", version.ref = "kotlin" }
googleHilt = { id = "com.google.dagger.hilt.android", version.ref = "hilt" }
googleKsp = { id = "com.google.devtools.ksp", version.ref = "ksp" }
googleGms = { id = "com.google.gms.google-services", version.ref = "gms" }