diff --git a/app/build.gradle b/app/build.gradle
index 5823addc..5643cbe8 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -1,8 +1,8 @@
plugins {
id 'com.android.application'
id 'org.jetbrains.kotlin.android'
- id 'kotlin-kapt'
id 'dagger.hilt.android.plugin'
+ id 'kotlin-kapt'
}
android {
@@ -10,16 +10,17 @@ android {
defaultConfig {
applicationId "com.mhss.app.mybrain"
+ namespace "com.mhss.app.mybrain"
minSdk 24
targetSdk 33
- versionCode 3
- versionName "1.0.2"
+ versionCode 4
+ versionName "1.0.3"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
vectorDrawables {
useSupportLibrary true
}
- resConfigs "en", "ar", "zh-rCN", "hi", "pl", "ru"
+ resConfigs "en", "ar", "zh-rCN", "hi", "pl", "ru", "ro", "pt-rBR", "de"
kapt {
arguments {
arg("room.schemaLocation", "$projectDir/schemas")
@@ -69,27 +70,28 @@ kotlin {
}
dependencies {
- def nav_version = "2.5.1"
def room_version = "2.4.3"
def coroutines_version = "1.6.1"
- implementation 'androidx.core:core-ktx:1.8.0'
- implementation "androidx.compose.ui:ui:$compose_version"
- implementation "androidx.compose.material:material:$compose_version"
- implementation "androidx.compose.ui:ui-tooling-preview:$compose_version"
+ implementation platform('androidx.compose:compose-bom:2022.10.00')
+
+ implementation 'androidx.core:core-ktx:1.9.0'
+ implementation "androidx.compose.ui:ui"
+ implementation "androidx.compose.material:material"
+ implementation "androidx.compose.ui:ui-tooling-preview"
implementation 'androidx.lifecycle:lifecycle-runtime-ktx:2.5.1'
- implementation 'androidx.activity:activity-compose:1.5.1'
+ implementation 'androidx.activity:activity-compose:1.6.0'
testImplementation 'junit:junit:4.13.2'
androidTestImplementation 'androidx.test.ext:junit:1.1.3'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'
- androidTestImplementation "androidx.compose.ui:ui-test-junit4:$compose_version"
- debugImplementation "androidx.compose.ui:ui-tooling:$compose_version"
+ androidTestImplementation "androidx.compose.ui:ui-test-junit4"
+ debugImplementation "androidx.compose.ui:ui-tooling"
// Compose navigation
- implementation "androidx.navigation:navigation-compose:$nav_version"
+ implementation "androidx.navigation:navigation-compose:2.5.2"
implementation 'androidx.hilt:hilt-navigation-compose:1.0.0'
-// Room
+ // Room
implementation "androidx.room:room-runtime:$room_version"
kapt "androidx.room:room-compiler:$room_version"
implementation "androidx.room:room-ktx:$room_version"
@@ -98,13 +100,14 @@ dependencies {
implementation "com.google.dagger:hilt-android:2.43.2"
kapt "com.google.dagger:hilt-android-compiler:2.43.2"
kapt "androidx.hilt:hilt-compiler:1.0.0"
+ implementation 'androidx.hilt:hilt-work:1.0.0'
// Coroutines
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:$coroutines_version"
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:$coroutines_version"
// Gson
- implementation 'com.google.code.gson:gson:2.9.0'
+ implementation 'com.google.code.gson:gson:2.9.1'
// Preferences DataStore
implementation "androidx.datastore:datastore-preferences:1.0.0"
@@ -118,8 +121,16 @@ dependencies {
implementation 'com.github.jeziellago:compose-markdown:0.2.9'
// Compose Glance (Widgets)
- implementation "androidx.glance:glance-appwidget:1.0.0-alpha03"
+ implementation "androidx.glance:glance-appwidget:1.0.0-alpha05"
+
+ //Moshi
+ implementation "com.squareup.moshi:moshi-kotlin:1.14.0"
+
+ // WorkManager
+ implementation "androidx.work:work-runtime-ktx:2.7.1"
+ // Compose live data
+ implementation "androidx.compose.runtime:runtime-livedata"
}
kapt {
diff --git a/app/proguard-rules.pro b/app/proguard-rules.pro
index 481bb434..16f03358 100644
--- a/app/proguard-rules.pro
+++ b/app/proguard-rules.pro
@@ -18,4 +18,5 @@
# If you keep the line number information, uncomment this to
# hide the original source file name.
-#-renamesourcefileattribute SourceFile
\ No newline at end of file
+#-renamesourcefileattribute SourceFile
+-dontobfuscate
\ No newline at end of file
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 8c608968..ebdc311a 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -1,7 +1,6 @@
+ xmlns:tools="http://schemas.android.com/tools">
@@ -9,23 +8,26 @@
+
+
+ android:windowSoftInputMode="adjustResize">
@@ -95,8 +97,8 @@
+ android:exported="true"
+ android:label="@string/calendar">
@@ -111,9 +113,10 @@
android:enabled="@bool/glance_appwidget_available"
android:exported="true">
-
-
-
+
+
+
+
@@ -121,8 +124,8 @@
+ android:exported="false"
+ android:label="@string/tasks">
@@ -134,8 +137,14 @@
-
+ android:exported="false" />
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/java/com/mhss/app/mybrain/app/MyBrainApplication.kt b/app/src/main/java/com/mhss/app/mybrain/app/MyBrainApplication.kt
index 4c61174d..a1d95f6d 100644
--- a/app/src/main/java/com/mhss/app/mybrain/app/MyBrainApplication.kt
+++ b/app/src/main/java/com/mhss/app/mybrain/app/MyBrainApplication.kt
@@ -9,19 +9,30 @@ import androidx.annotation.StringRes
import androidx.datastore.core.DataStore
import androidx.datastore.preferences.core.Preferences
import androidx.datastore.preferences.preferencesDataStore
+import androidx.hilt.work.HiltWorkerFactory
+import androidx.work.Configuration
import com.mhss.app.mybrain.R
import com.mhss.app.mybrain.util.Constants
import dagger.hilt.android.HiltAndroidApp
+import javax.inject.Inject
val Context.dataStore: DataStore by preferencesDataStore(name = Constants.SETTINGS_PREFERENCES)
@HiltAndroidApp
-class MyBrainApplication : Application() {
+class MyBrainApplication : Application(), Configuration.Provider {
companion object {
lateinit var appContext: Context
}
+ @Inject
+ lateinit var workerFactory: HiltWorkerFactory
+
+ override fun getWorkManagerConfiguration() =
+ Configuration.Builder()
+ .setWorkerFactory(workerFactory)
+ .build()
+
override fun onCreate() {
super.onCreate()
appContext = this
diff --git a/app/src/main/java/com/mhss/app/mybrain/data/backup/ExportWorker.kt b/app/src/main/java/com/mhss/app/mybrain/data/backup/ExportWorker.kt
new file mode 100644
index 00000000..8736102d
--- /dev/null
+++ b/app/src/main/java/com/mhss/app/mybrain/data/backup/ExportWorker.kt
@@ -0,0 +1,123 @@
+package com.mhss.app.mybrain.data.backup
+
+import android.content.ContentUris
+import android.content.ContentValues
+import android.content.Context
+import android.net.Uri
+import android.os.Build
+import android.os.Environment
+import android.provider.MediaStore
+import androidx.hilt.work.HiltWorker
+import androidx.work.CoroutineWorker
+import androidx.work.WorkerParameters
+import androidx.work.workDataOf
+import com.mhss.app.mybrain.data.local.dao.BookmarkDao
+import com.mhss.app.mybrain.data.local.dao.DiaryDao
+import com.mhss.app.mybrain.data.local.dao.NoteDao
+import com.mhss.app.mybrain.data.local.dao.TaskDao
+import com.mhss.app.mybrain.domain.model.NotesBackUp
+import com.mhss.app.mybrain.util.BackupUtil.toJson
+import com.mhss.app.mybrain.util.Constants
+import dagger.assisted.Assisted
+import dagger.assisted.AssistedInject
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.flow.first
+import kotlinx.coroutines.withContext
+import java.io.File
+import java.io.FileOutputStream
+
+
+@HiltWorker
+class ExportWorker @AssistedInject constructor(
+ @Assisted appContext: Context,
+ @Assisted workerParams: WorkerParameters,
+ private val notesDao: NoteDao,
+ private val tasksDao: TaskDao,
+ private val diaryDao: DiaryDao,
+ private val bookmarksDao: BookmarkDao
+) : CoroutineWorker(appContext, workerParams) {
+
+ override suspend fun doWork() = withContext(Dispatchers.IO) {
+ export()
+ }
+
+ private suspend fun export(): Result {
+ return try {
+ val notes = notesDao.getAllNotes().first()
+ val folders = notesDao.getAllNoteFolders().first()
+ val notesBackup = NotesBackUp(notes, folders).toJson()
+ saveFile(Constants.BACKUP_NOTES_FILE_NAME, notesBackup)
+ setProgress(workDataOf("progress" to 25))
+
+ val tasks = tasksDao.getAllTasks().first().toJson()
+ saveFile(Constants.BACKUP_TASKS_FILE_NAME, tasks)
+ setProgress(workDataOf("progress" to 50))
+
+ val diary = diaryDao.getAllEntries().first().toJson()
+ saveFile(Constants.BACKUP_DIARY_FILE_NAME, diary)
+ setProgress(workDataOf("progress" to 75))
+
+ val bookmarks = bookmarksDao.getAllBookmarks().first().toJson()
+ saveFile(Constants.BACKUP_BOOKMARKS_FILE_NAME, bookmarks)
+ setProgress(workDataOf("progress" to 100))
+
+ Result.success(workDataOf("success" to true))
+ } catch (e: Exception) {
+ e.printStackTrace()
+ Result.failure()
+ }
+ }
+
+
+ private fun saveFile(fileName: String, content: String) {
+ val contentResolver = applicationContext.contentResolver
+ val values = ContentValues().apply {
+ put(MediaStore.MediaColumns.DISPLAY_NAME, fileName)
+ put(MediaStore.MediaColumns.MIME_TYPE,"text/plain")
+ }
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
+ values.put(MediaStore.MediaColumns.RELATIVE_PATH, Environment.DIRECTORY_DOCUMENTS + File.separator + "${Constants.EXPORT_DIR}/")
+ }
+ val fileUri = getFileUri(fileName) ?: contentResolver.insert(MediaStore.Files.getContentUri("external"), values)
+
+ fileUri?.let {
+ contentResolver.openFileDescriptor(it, "w")?.use { pfd ->
+ FileOutputStream(pfd.fileDescriptor).use { outputStream ->
+ outputStream.write(content.toByteArray())
+ }
+ }
+ }
+ }
+
+ private fun getFileUri(name: String): Uri? {
+ val projection = arrayOf(
+ MediaStore.Files.FileColumns._ID,
+ MediaStore.Files.FileColumns.DISPLAY_NAME
+ )
+ val selection = "${MediaStore.MediaColumns.RELATIVE_PATH} = ? AND ${MediaStore.Files.FileColumns.DISPLAY_NAME} = ?"
+ val selectionArgs = arrayOf(
+ Environment.DIRECTORY_DOCUMENTS + File.separator + "${Constants.EXPORT_DIR}/",
+ name
+ )
+ val resolver = applicationContext.contentResolver
+ val query = resolver.query(
+ MediaStore.Files.getContentUri("external"),
+ projection,
+ selection,
+ selectionArgs,
+ null
+ )
+ query?.use { cursor ->
+ val idColumn = cursor.getColumnIndexOrThrow(MediaStore.Files.FileColumns._ID)
+ if (cursor.moveToFirst()) {
+ val id = cursor.getLong(idColumn)
+ return ContentUris.withAppendedId(
+ MediaStore.Files.getContentUri("external"),
+ id
+ )
+ }
+ }
+ return null
+ }
+
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/mhss/app/mybrain/data/backup/ImportWorker.kt b/app/src/main/java/com/mhss/app/mybrain/data/backup/ImportWorker.kt
new file mode 100644
index 00000000..f52778a0
--- /dev/null
+++ b/app/src/main/java/com/mhss/app/mybrain/data/backup/ImportWorker.kt
@@ -0,0 +1,119 @@
+package com.mhss.app.mybrain.data.backup
+
+import android.content.ContentResolver
+import android.content.Context
+import android.net.Uri
+import android.provider.OpenableColumns
+import androidx.hilt.work.HiltWorker
+import androidx.work.CoroutineWorker
+import androidx.work.WorkerParameters
+import androidx.work.workDataOf
+import com.mhss.app.mybrain.R
+import com.mhss.app.mybrain.app.getString
+import com.mhss.app.mybrain.data.local.dao.BookmarkDao
+import com.mhss.app.mybrain.data.local.dao.DiaryDao
+import com.mhss.app.mybrain.data.local.dao.NoteDao
+import com.mhss.app.mybrain.data.local.dao.TaskDao
+import com.mhss.app.mybrain.domain.model.Bookmark
+import com.mhss.app.mybrain.domain.model.DiaryEntry
+import com.mhss.app.mybrain.domain.model.NotesBackUp
+import com.mhss.app.mybrain.domain.model.Task
+import com.mhss.app.mybrain.util.BackupUtil.listFromJson
+import com.mhss.app.mybrain.util.BackupUtil.objectFromJson
+import com.mhss.app.mybrain.util.Constants
+import dagger.assisted.Assisted
+import dagger.assisted.AssistedInject
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.withContext
+import java.io.FileInputStream
+
+@HiltWorker
+class ImportWorker @AssistedInject constructor(
+ @Assisted appContext: Context,
+ @Assisted workerParams: WorkerParameters,
+ private val notesDao: NoteDao,
+ private val tasksDao: TaskDao,
+ private val diaryDao: DiaryDao,
+ private val bookmarksDao: BookmarkDao
+) : CoroutineWorker(appContext, workerParams) {
+
+ override suspend fun doWork() = withContext(Dispatchers.IO) {
+
+ val backupDir = inputData.getString("uri") ?: return@withContext Result.failure()
+
+ import(backupDir)
+
+ }
+
+ private suspend fun import(uriString: String?): Result {
+ val contentResolver = applicationContext.contentResolver
+
+ val uri = Uri.parse(uriString)
+ val fileName = uri.fileName()
+
+ uri?.let {
+ val json = contentResolver.readTextFromFile(uri)
+ json?.let {
+ try {
+ return when(fileName){
+ Constants.BACKUP_NOTES_FILE_NAME -> {
+ val notesObject = json.objectFromJson() ?: return Result.failure()
+ val folders = notesObject.folders.map{it.copy(id = 0)}
+ val notes = notesObject.notes.map{it.copy(id = 0, folderId = null)}
+ notesDao.insertNoteFolders(folders)
+ notesDao.insertNotes(notes)
+ Result.success(workDataOf("success" to getString(R.string.notes)))
+ }
+ Constants.BACKUP_TASKS_FILE_NAME -> {
+ val tasks = json.listFromJson()?.map{it.copy(id = 0)} ?: return Result.failure()
+ tasksDao.insertTasks(tasks)
+ Result.success(workDataOf("success" to getString(R.string.tasks)))
+ }
+ Constants.BACKUP_DIARY_FILE_NAME -> {
+ val diaryEntries = json.listFromJson()?.map{it.copy(id = 0)} ?: return Result.failure()
+ diaryDao.insertEntries(diaryEntries)
+ Result.success(workDataOf("success" to getString(R.string.diary)))
+ }
+ Constants.BACKUP_BOOKMARKS_FILE_NAME -> {
+ val bookmarks = json.listFromJson()?.map{it.copy(id = 0)} ?: return Result.failure()
+ bookmarksDao.insertBookmarks(bookmarks)
+ Result.success(workDataOf("success" to getString(R.string.bookmarks)))
+ }
+ else -> Result.failure()
+ }
+ }catch (e: Exception){
+ return Result.failure()
+ }
+ }
+ } ?: return Result.failure()
+ }
+
+ private fun ContentResolver.readTextFromFile(uri: Uri?): String? {
+ return uri?.let {
+ openFileDescriptor(uri, "r")?.use { pfd ->
+ FileInputStream(pfd.fileDescriptor).use { inputStream ->
+ inputStream.bufferedReader().use { it.readText() }
+ }
+ }
+ }
+ }
+
+ private fun Uri.fileName(): String {
+ val resolver = applicationContext.contentResolver
+ val query = resolver.query(
+ this,
+ null,
+ null,
+ null,
+ null
+ )
+ query?.use { cursor ->
+ val id = cursor.getColumnIndex(OpenableColumns.DISPLAY_NAME)
+ while (cursor.moveToNext()) {
+ return cursor.getString(id)
+ }
+ }
+ return ""
+ }
+
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/mhss/app/mybrain/data/local/dao/BookmarkDao.kt b/app/src/main/java/com/mhss/app/mybrain/data/local/dao/BookmarkDao.kt
index ca6e8bb3..98d2aa43 100644
--- a/app/src/main/java/com/mhss/app/mybrain/data/local/dao/BookmarkDao.kt
+++ b/app/src/main/java/com/mhss/app/mybrain/data/local/dao/BookmarkDao.kt
@@ -8,7 +8,7 @@ import kotlinx.coroutines.flow.Flow
interface BookmarkDao {
@Query("SELECT * FROM bookmarks")
- fun getAll(): Flow>
+ fun getAllBookmarks(): Flow>
@Query("SELECT * FROM bookmarks WHERE id = :id")
suspend fun getBookmark(id: Int): Bookmark
@@ -25,4 +25,7 @@ interface BookmarkDao {
@Delete
suspend fun deleteBookmark(bookmark: Bookmark)
+ @Insert
+ suspend fun insertBookmarks(bookmarks: List)
+
}
\ No newline at end of file
diff --git a/app/src/main/java/com/mhss/app/mybrain/data/local/dao/DiaryDao.kt b/app/src/main/java/com/mhss/app/mybrain/data/local/dao/DiaryDao.kt
index ac79fb77..29780490 100644
--- a/app/src/main/java/com/mhss/app/mybrain/data/local/dao/DiaryDao.kt
+++ b/app/src/main/java/com/mhss/app/mybrain/data/local/dao/DiaryDao.kt
@@ -19,6 +19,9 @@ interface DiaryDao {
@Insert
suspend fun insertEntry(diary: DiaryEntry)
+ @Insert
+ suspend fun insertEntries(diary: List)
+
@Update
suspend fun updateEntry(diary: DiaryEntry)
diff --git a/app/src/main/java/com/mhss/app/mybrain/data/local/dao/NoteDao.kt b/app/src/main/java/com/mhss/app/mybrain/data/local/dao/NoteDao.kt
index f8124a09..23432216 100644
--- a/app/src/main/java/com/mhss/app/mybrain/data/local/dao/NoteDao.kt
+++ b/app/src/main/java/com/mhss/app/mybrain/data/local/dao/NoteDao.kt
@@ -23,6 +23,9 @@ interface NoteDao {
@Insert(onConflict = OnConflictStrategy.REPLACE)
suspend fun insertNote(note: Note)
+ @Insert(onConflict = OnConflictStrategy.IGNORE)
+ suspend fun insertNotes(notes: List)
+
@Update
suspend fun updateNote(note: Note)
@@ -32,6 +35,9 @@ interface NoteDao {
@Insert(onConflict = OnConflictStrategy.IGNORE)
suspend fun insertNoteFolder(folder: NoteFolder)
+ @Insert(onConflict = OnConflictStrategy.IGNORE)
+ suspend fun insertNoteFolders(folders: List)
+
@Update
suspend fun updateNoteFolder(folder: NoteFolder)
diff --git a/app/src/main/java/com/mhss/app/mybrain/data/local/dao/TaskDao.kt b/app/src/main/java/com/mhss/app/mybrain/data/local/dao/TaskDao.kt
index bb878032..63237315 100644
--- a/app/src/main/java/com/mhss/app/mybrain/data/local/dao/TaskDao.kt
+++ b/app/src/main/java/com/mhss/app/mybrain/data/local/dao/TaskDao.kt
@@ -19,6 +19,9 @@ interface TaskDao {
@Insert(onConflict = OnConflictStrategy.REPLACE)
suspend fun insertTask(task: Task): Long
+ @Insert(onConflict = OnConflictStrategy.IGNORE)
+ suspend fun insertTasks(tasks: List)
+
@Update
suspend fun updateTask(task: Task)
diff --git a/app/src/main/java/com/mhss/app/mybrain/data/repository/BookmarkRepositoryImpl.kt b/app/src/main/java/com/mhss/app/mybrain/data/repository/BookmarkRepositoryImpl.kt
index 87b4ccab..d8b390a5 100644
--- a/app/src/main/java/com/mhss/app/mybrain/data/repository/BookmarkRepositoryImpl.kt
+++ b/app/src/main/java/com/mhss/app/mybrain/data/repository/BookmarkRepositoryImpl.kt
@@ -14,7 +14,7 @@ class BookmarkRepositoryImpl(
) : BookmarkRepository {
override fun getAllBookmarks(): Flow> {
- return bookmarkDao.getAll()
+ return bookmarkDao.getAllBookmarks()
}
override suspend fun getBookmark(id: Int): Bookmark {
diff --git a/app/src/main/java/com/mhss/app/mybrain/data/repository/CalendarRepositoryImpl.kt b/app/src/main/java/com/mhss/app/mybrain/data/repository/CalendarRepositoryImpl.kt
index 299b9536..958bff24 100644
--- a/app/src/main/java/com/mhss/app/mybrain/data/repository/CalendarRepositoryImpl.kt
+++ b/app/src/main/java/com/mhss/app/mybrain/data/repository/CalendarRepositoryImpl.kt
@@ -26,24 +26,39 @@ class CalendarRepositoryImpl(private val context: Context) : CalendarRepository
CalendarContract.Events.DTEND,
CalendarContract.Events.EVENT_LOCATION,
CalendarContract.Events.ALL_DAY,
- CalendarContract.Events.CALENDAR_COLOR,
+ CalendarContract.Events.EVENT_COLOR,
CalendarContract.Events.CALENDAR_ID,
CalendarContract.Events.RRULE,
CalendarContract.Events.DURATION,
+ CalendarContract.Events.CALENDAR_COLOR
)
+ val instancesProjection = arrayOf(
+ CalendarContract.Instances.EVENT_ID,
+ CalendarContract.Instances.TITLE,
+ CalendarContract.Instances.DESCRIPTION,
+ CalendarContract.Instances.BEGIN,
+ CalendarContract.Instances.END,
+ CalendarContract.Instances.EVENT_LOCATION,
+ CalendarContract.Instances.ALL_DAY,
+ CalendarContract.Instances.EVENT_COLOR,
+ CalendarContract.Instances.CALENDAR_ID,
+ CalendarContract.Instances.RRULE,
+ CalendarContract.Instances.DURATION,
+ CalendarContract.Instances.CALENDAR_COLOR
+ )
+ val contentResolver = context.contentResolver
+ val events = mutableListOf()
val uri: Uri = CalendarContract.Events.CONTENT_URI
- val contentResolver = context.contentResolver
val cur: Cursor? = contentResolver.query(
uri,
projection,
"${CalendarContract.Events.DTSTART} > ? AND ${CalendarContract.Events.DELETED} = 0",
// events today or in the future only
arrayOf(System.currentTimeMillis().toString()),
- "${CalendarContract.Events.DTSTART} ASC"
+ null
)
- val events: MutableList = mutableListOf()
if (cur != null) {
while (cur.moveToNext()) {
val eventId: Long = cur.getLong(ID_INDEX)
@@ -55,11 +70,55 @@ class CalendarRepositoryImpl(private val context: Context) : CalendarRepository
val location: String? = cur.getString(LOCATION_INDEX)
val allDay: Boolean = cur.getInt(ALL_DAY_INDEX) == 1
val color: Int = cur.getInt(COlOR_INDEX)
+ val calendarColor: Int = cur.getInt(CALENDAR_COLOR_INDEX)
val calendarId: Long = cur.getLong(EVENT_CALENDAR_ID_INDEX)
val rrule: String = cur.getString(EVENT_RRULE_INDEX) ?: ""
val recurring: Boolean = rrule.isNotBlank()
- val frequency: String = rrule.extractFrequency()
+// val frequency: String = rrule.extractFrequency()
+
+ if (!recurring)
+ events.add(CalendarEvent(
+ id = eventId ,
+ title = title,
+ description = description,
+ start = start,
+ end = end,
+ location = location,
+ allDay = allDay,
+ color = if (color != 0) color else calendarColor,
+ calendarId = calendarId,
+ ))
+ }
+ cur.close()
+ }
+ // get recurring events
+ val startM = java.util.Calendar.getInstance().timeInMillis
+ val endM = startM + 6 * 30 * 24 * 60 * 60 * 1000L
+ val builder = CalendarContract.Instances.CONTENT_URI.buildUpon()
+ ContentUris.appendId(builder, startM)
+ ContentUris.appendId(builder, endM)
+ val curI = contentResolver.query(
+ builder.build(),
+ instancesProjection,
+ null, null, null
+ )
+ if (curI != null){
+ while (curI.moveToNext()){
+ val eventId: Long = curI.getLong(ID_INDEX)
+ val title: String = curI.getString(TITLE_INDEX) ?: continue
+ val description: String? = curI.getString(DESC_INDEX)
+ val start: Long = curI.getLong(START_INDEX)
+ val duration: String = curI.getString(EVENT_DURATION_INDEX) ?: ""
+ val end: Long = if (duration.isNotBlank()) duration.extractEndFromDuration(start) else curI.getLong(END_INDEX)
+ val location: String? = curI.getString(LOCATION_INDEX)
+ val allDay: Boolean = curI.getInt(ALL_DAY_INDEX) == 1
+ val color: Int = curI.getInt(COlOR_INDEX)
+ val calendarColor: Int = curI.getInt(CALENDAR_COLOR_INDEX)
+ val calendarId: Long = curI.getLong(EVENT_CALENDAR_ID_INDEX)
+ val rrule: String = curI.getString(EVENT_RRULE_INDEX) ?: ""
+ val recurring: Boolean = rrule.isNotBlank()
+ val frequency: String = rrule.extractFrequency()
events.add(CalendarEvent(
id = eventId,
title = title,
@@ -68,16 +127,15 @@ class CalendarRepositoryImpl(private val context: Context) : CalendarRepository
end = end,
location = location,
allDay = allDay,
- color = color,
+ color = if (color != 0) color else calendarColor,
calendarId = calendarId,
frequency = frequency,
recurring = recurring,
))
}
- cur.close()
- events
- }else
- emptyList()
+ curI.close()
+ }
+ events.sortedBy { it.start }
}
}
@@ -191,6 +249,7 @@ class CalendarRepositoryImpl(private val context: Context) : CalendarRepository
private const val EVENT_CALENDAR_ID_INDEX = 8
private const val EVENT_RRULE_INDEX = 9
private const val EVENT_DURATION_INDEX = 10
+ private const val CALENDAR_COLOR_INDEX = 11
private const val CALENDAR_ID_INDEX: Int = 0
private const val CALENDAR_NAME_INDEX: Int = 1
diff --git a/app/src/main/java/com/mhss/app/mybrain/domain/model/NotesBackUp.kt b/app/src/main/java/com/mhss/app/mybrain/domain/model/NotesBackUp.kt
new file mode 100644
index 00000000..49791e1a
--- /dev/null
+++ b/app/src/main/java/com/mhss/app/mybrain/domain/model/NotesBackUp.kt
@@ -0,0 +1,6 @@
+package com.mhss.app.mybrain.domain.model
+
+data class NotesBackUp(
+ val notes: List,
+ val folders: List
+)
diff --git a/app/src/main/java/com/mhss/app/mybrain/domain/use_case/calendar/GetAllEventsUseCase.kt b/app/src/main/java/com/mhss/app/mybrain/domain/use_case/calendar/GetAllEventsUseCase.kt
index f1c22ad7..994def6a 100644
--- a/app/src/main/java/com/mhss/app/mybrain/domain/use_case/calendar/GetAllEventsUseCase.kt
+++ b/app/src/main/java/com/mhss/app/mybrain/domain/use_case/calendar/GetAllEventsUseCase.kt
@@ -2,7 +2,7 @@ package com.mhss.app.mybrain.domain.use_case.calendar
import com.mhss.app.mybrain.domain.model.CalendarEvent
import com.mhss.app.mybrain.domain.repository.CalendarRepository
-import com.mhss.app.mybrain.util.date.formatDay
+import com.mhss.app.mybrain.util.date.formatDateForMapping
import javax.inject.Inject
class GetAllEventsUseCase @Inject constructor(
@@ -12,7 +12,7 @@ class GetAllEventsUseCase @Inject constructor(
return calendarRepository.getEvents()
.filter { it.calendarId.toInt() !in excluded }
.groupBy { event ->
- event.start.formatDay()
+ event.start.formatDateForMapping()
}
}
}
\ No newline at end of file
diff --git a/app/src/main/java/com/mhss/app/mybrain/presentation/calendar/CalendarEventWidgetItem.kt b/app/src/main/java/com/mhss/app/mybrain/presentation/calendar/CalendarEventWidgetItem.kt
index 973a1c88..b9a0f711 100644
--- a/app/src/main/java/com/mhss/app/mybrain/presentation/calendar/CalendarEventWidgetItem.kt
+++ b/app/src/main/java/com/mhss/app/mybrain/presentation/calendar/CalendarEventWidgetItem.kt
@@ -30,13 +30,6 @@ fun CalendarEventWidgetItem(
Box(
GlanceModifier
.padding(vertical = 4.dp)
- .clickable(
- onClick = actionRunCallback(
- parameters = actionParametersOf(
- eventJson to Gson().toJson(event, CalendarEvent::class.java)
- )
- )
- )
) {
Box(
modifier = GlanceModifier
@@ -81,6 +74,13 @@ fun CalendarEventWidgetItem(
)
}
}
+ Box(GlanceModifier.fillMaxSize().clickable(
+ actionRunCallback(
+ parameters = actionParametersOf(
+ eventJson to Gson().toJson(event, CalendarEvent::class.java)
+ )
+ )
+ )) {}
}
}
}
\ No newline at end of file
diff --git a/app/src/main/java/com/mhss/app/mybrain/presentation/calendar/CalendarHomeScreenWidget.kt b/app/src/main/java/com/mhss/app/mybrain/presentation/calendar/CalendarHomeScreenWidget.kt
index 2cb144ac..16452ecd 100644
--- a/app/src/main/java/com/mhss/app/mybrain/presentation/calendar/CalendarHomeScreenWidget.kt
+++ b/app/src/main/java/com/mhss/app/mybrain/presentation/calendar/CalendarHomeScreenWidget.kt
@@ -36,7 +36,6 @@ fun CalendarHomeScreenWidget(
) {
Column(
modifier = GlanceModifier
- .clickable(onClick = actionRunCallback())
.padding(8.dp)
) {
Row(
@@ -51,30 +50,33 @@ fun CalendarHomeScreenWidget(
fontWeight = FontWeight.Bold,
fontSize = 16.sp
),
- modifier = GlanceModifier.padding(horizontal = 8.dp),
+ modifier = GlanceModifier
+ .padding(horizontal = 8.dp)
+ .clickable(onClick = actionRunCallback())
+ ,
)
Row(
- modifier = GlanceModifier.fillMaxWidth().padding(horizontal = 8.dp),
+ modifier = GlanceModifier
+ .clickable(onClick = actionRunCallback())
+ .fillMaxWidth()
+ .padding(horizontal = 8.dp),
horizontalAlignment = Alignment.End
) {
- Button(
- text = "",
+ Image(
modifier = GlanceModifier
.size(22.dp)
- .background(ImageProvider(R.drawable.ic_refresh))
- .padding(8.dp)
- ,
- onClick = actionRunCallback()
+ .clickable(actionRunCallback()),
+ provider = ImageProvider(R.drawable.ic_refresh),
+ contentDescription = "refresh"
)
Spacer(GlanceModifier.width(12.dp))
- Button(
- text = "",
+ Image(
modifier = GlanceModifier
.size(22.dp)
- .background(ImageProvider(R.drawable.ic_add))
- .padding(8.dp)
+ .clickable(actionRunCallback())
,
- onClick = actionRunCallback()
+ provider = ImageProvider(R.drawable.ic_add),
+ contentDescription = "add event",
)
}
}
@@ -109,7 +111,7 @@ fun CalendarHomeScreenWidget(
.padding(start = 4.dp, end = 4.dp)
) {
Text(
- text = day,
+ text = day.substring(0, day.indexOf(",")),
style = TextStyle(
color = ColorProvider(Color.White),
fontWeight = FontWeight.Normal,
diff --git a/app/src/main/java/com/mhss/app/mybrain/presentation/calendar/CalendarScreen.kt b/app/src/main/java/com/mhss/app/mybrain/presentation/calendar/CalendarScreen.kt
index cf88e572..94bff016 100644
--- a/app/src/main/java/com/mhss/app/mybrain/presentation/calendar/CalendarScreen.kt
+++ b/app/src/main/java/com/mhss/app/mybrain/presentation/calendar/CalendarScreen.kt
@@ -152,7 +152,7 @@ fun CalendarScreen(
verticalArrangement = Arrangement.spacedBy(12.dp),
) {
Text(
- text = day,
+ text = day.substring(0, day.indexOf(",")),
style = MaterialTheme.typography.h5
)
events.forEach { event ->
diff --git a/app/src/main/java/com/mhss/app/mybrain/presentation/glance_widgets/CalendarWidgetActions.kt b/app/src/main/java/com/mhss/app/mybrain/presentation/glance_widgets/CalendarWidgetActions.kt
index b8386281..7fe970c1 100644
--- a/app/src/main/java/com/mhss/app/mybrain/presentation/glance_widgets/CalendarWidgetActions.kt
+++ b/app/src/main/java/com/mhss/app/mybrain/presentation/glance_widgets/CalendarWidgetActions.kt
@@ -12,7 +12,7 @@ import com.mhss.app.mybrain.presentation.main.MainActivity
import com.mhss.app.mybrain.util.Constants
class AddEventAction : ActionCallback {
- override suspend fun onRun(context: Context, glanceId: GlanceId, parameters: ActionParameters) {
+ override suspend fun onAction(context: Context, glanceId: GlanceId, parameters: ActionParameters) {
val intent = Intent(
Intent.ACTION_VIEW,
"${Constants.CALENDAR_DETAILS_SCREEN_URI}/ ".toUri(),
@@ -24,7 +24,7 @@ class AddEventAction : ActionCallback {
}
class NavigateToCalendarAction : ActionCallback {
- override suspend fun onRun(context: Context, glanceId: GlanceId, parameters: ActionParameters) {
+ override suspend fun onAction(context: Context, glanceId: GlanceId, parameters: ActionParameters) {
val intent = Intent(
Intent.ACTION_VIEW,
Constants.CALENDAR_SCREEN_URI.toUri(),
@@ -36,7 +36,7 @@ class NavigateToCalendarAction : ActionCallback {
}
class CalendarWidgetItemClick : ActionCallback {
- override suspend fun onRun(context: Context, glanceId: GlanceId, parameters: ActionParameters) {
+ override suspend fun onAction(context: Context, glanceId: GlanceId, parameters: ActionParameters) {
parameters[eventJson]?.let {
val intent = Intent(
Intent.ACTION_VIEW,
@@ -50,7 +50,7 @@ class CalendarWidgetItemClick : ActionCallback {
}
class GoToSettingsAction : ActionCallback {
- override suspend fun onRun(context: Context, glanceId: GlanceId, parameters: ActionParameters) {
+ override suspend fun onAction(context: Context, glanceId: GlanceId, parameters: ActionParameters) {
val intent = Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS).addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
intent.data = Uri.fromParts("package", context.packageName, null)
context.startActivity(intent)
@@ -58,7 +58,7 @@ class GoToSettingsAction : ActionCallback {
}
class RefreshCalendarAction : ActionCallback {
- override suspend fun onRun(context: Context, glanceId: GlanceId, parameters: ActionParameters) {
+ override suspend fun onAction(context: Context, glanceId: GlanceId, parameters: ActionParameters) {
val updateIntent = Intent(context, RefreshCalendarWidgetReceiver::class.java)
context.sendBroadcast(updateIntent)
}
diff --git a/app/src/main/java/com/mhss/app/mybrain/presentation/glance_widgets/TasksWidgetActions.kt b/app/src/main/java/com/mhss/app/mybrain/presentation/glance_widgets/TasksWidgetActions.kt
index 003a8d76..421aa15d 100644
--- a/app/src/main/java/com/mhss/app/mybrain/presentation/glance_widgets/TasksWidgetActions.kt
+++ b/app/src/main/java/com/mhss/app/mybrain/presentation/glance_widgets/TasksWidgetActions.kt
@@ -10,7 +10,7 @@ import com.mhss.app.mybrain.presentation.main.MainActivity
import com.mhss.app.mybrain.util.Constants
class AddTaskAction : ActionCallback {
- override suspend fun onRun(context: Context, glanceId: GlanceId, parameters: ActionParameters) {
+ override suspend fun onAction(context: Context, glanceId: GlanceId, parameters: ActionParameters) {
val intent = Intent(
Intent.ACTION_VIEW,
"${Constants.TASKS_SCREEN_URI}/true".toUri(),
@@ -22,7 +22,7 @@ class AddTaskAction : ActionCallback {
}
class NavigateToTasksAction : ActionCallback {
- override suspend fun onRun(context: Context, glanceId: GlanceId, parameters: ActionParameters) {
+ override suspend fun onAction(context: Context, glanceId: GlanceId, parameters: ActionParameters) {
val intent = Intent(
Intent.ACTION_VIEW,
"${Constants.TASKS_SCREEN_URI}/false".toUri(),
@@ -34,7 +34,7 @@ class NavigateToTasksAction : ActionCallback {
}
class TaskWidgetItemClickAction : ActionCallback {
- override suspend fun onRun(context: Context, glanceId: GlanceId, parameters: ActionParameters) {
+ override suspend fun onAction(context: Context, glanceId: GlanceId, parameters: ActionParameters) {
parameters[taskId]?.let {
val intent = Intent(
Intent.ACTION_VIEW,
@@ -48,7 +48,7 @@ class TaskWidgetItemClickAction : ActionCallback {
}
class CompleteTaskAction : ActionCallback {
- override suspend fun onRun(context: Context, glanceId: GlanceId, parameters: ActionParameters) {
+ override suspend fun onAction(context: Context, glanceId: GlanceId, parameters: ActionParameters) {
parameters[taskId]?.let { id ->
parameters[completed].let { completed ->
val intent = Intent(context, CompleteTaskWidgetReceiver::class.java)
diff --git a/app/src/main/java/com/mhss/app/mybrain/presentation/main/MainActivity.kt b/app/src/main/java/com/mhss/app/mybrain/presentation/main/MainActivity.kt
index bec55c68..f194cb09 100644
--- a/app/src/main/java/com/mhss/app/mybrain/presentation/main/MainActivity.kt
+++ b/app/src/main/java/com/mhss/app/mybrain/presentation/main/MainActivity.kt
@@ -1,6 +1,7 @@
package com.mhss.app.mybrain.presentation.main
import android.os.Bundle
+import android.view.WindowManager.LayoutParams
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.activity.viewModels
@@ -31,6 +32,7 @@ import com.mhss.app.mybrain.presentation.diary.DiarySearchScreen
import com.mhss.app.mybrain.presentation.notes.NoteDetailsScreen
import com.mhss.app.mybrain.presentation.notes.NotesScreen
import com.mhss.app.mybrain.presentation.notes.NotesSearchScreen
+import com.mhss.app.mybrain.presentation.settings.ImportExportScreen
import com.mhss.app.mybrain.presentation.tasks.TaskDetailScreen
import com.mhss.app.mybrain.presentation.tasks.TasksScreen
import com.mhss.app.mybrain.presentation.tasks.TasksSearchScreen
@@ -58,6 +60,7 @@ class MainActivity : ComponentActivity() {
setContent {
val themeMode = viewModel.themeMode.collectAsState(initial = ThemeSettings.AUTO.value)
val font = viewModel.font.collectAsState(initial = Rubik.toInt())
+ val blockScreenshots = viewModel.blockScreenshots.collectAsState(initial = false)
var startUpScreenSettings by remember { mutableStateOf(StartUpScreenSettings.SPACES.value) }
val systemUiController = rememberSystemUiController()
LaunchedEffect(true) {
@@ -65,6 +68,15 @@ class MainActivity : ComponentActivity() {
startUpScreenSettings = viewModel.defaultStartUpScreen.first()
}
}
+ LaunchedEffect(blockScreenshots.value) {
+ if (blockScreenshots.value) {
+ window.setFlags(
+ LayoutParams.FLAG_SECURE,
+ LayoutParams.FLAG_SECURE
+ )
+ } else
+ window.clearFlags(LayoutParams.FLAG_SECURE)
+ }
val startUpScreen =
if (startUpScreenSettings == StartUpScreenSettings.SPACES.value)
Screen.SpacesScreen.route else Screen.DashboardScreen.route
@@ -234,6 +246,9 @@ class MainActivity : ComponentActivity() {
it.arguments?.getInt(Constants.FOLDER_ID) ?: -1
)
}
+ composable(Screen.ImportExportScreen.route) {
+ ImportExportScreen()
+ }
}
}
}
diff --git a/app/src/main/java/com/mhss/app/mybrain/presentation/main/MainViewModel.kt b/app/src/main/java/com/mhss/app/mybrain/presentation/main/MainViewModel.kt
index 8d74b090..86521f73 100644
--- a/app/src/main/java/com/mhss/app/mybrain/presentation/main/MainViewModel.kt
+++ b/app/src/main/java/com/mhss/app/mybrain/presentation/main/MainViewModel.kt
@@ -43,6 +43,7 @@ class MainViewModel @Inject constructor(
val themeMode = getSettings(intPreferencesKey(Constants.SETTINGS_THEME_KEY), ThemeSettings.AUTO.value)
val defaultStartUpScreen = getSettings(intPreferencesKey(Constants.DEFAULT_START_UP_SCREEN_KEY), StartUpScreenSettings.SPACES.value)
val font = getSettings(intPreferencesKey(Constants.APP_FONT_KEY), Rubik.toInt())
+ val blockScreenshots = getSettings(booleanPreferencesKey(Constants.BLOCK_SCREENSHOTS_KEY), false)
fun onDashboardEvent(event: DashboardEvent) {
when(event) {
diff --git a/app/src/main/java/com/mhss/app/mybrain/presentation/main/SettingsScreen.kt b/app/src/main/java/com/mhss/app/mybrain/presentation/main/SettingsScreen.kt
index 246587a4..6905ff4f 100644
--- a/app/src/main/java/com/mhss/app/mybrain/presentation/main/SettingsScreen.kt
+++ b/app/src/main/java/com/mhss/app/mybrain/presentation/main/SettingsScreen.kt
@@ -12,21 +12,24 @@ import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.font.FontFamily
import androidx.compose.ui.text.font.FontWeight
-import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
+import androidx.datastore.preferences.core.booleanPreferencesKey
import androidx.datastore.preferences.core.intPreferencesKey
import androidx.hilt.navigation.compose.hiltViewModel
+import androidx.navigation.NavHostController
import com.mhss.app.mybrain.BuildConfig
import com.mhss.app.mybrain.R
import com.mhss.app.mybrain.presentation.settings.SettingsBasicLinkItem
import com.mhss.app.mybrain.presentation.settings.SettingsItemCard
import com.mhss.app.mybrain.presentation.settings.SettingsViewModel
+import com.mhss.app.mybrain.presentation.util.Screen
import com.mhss.app.mybrain.ui.theme.Rubik
import com.mhss.app.mybrain.util.Constants
import com.mhss.app.mybrain.util.settings.*
@Composable
fun SettingsScreen(
+ navController: NavHostController,
viewModel: SettingsViewModel = hiltViewModel()
) {
Scaffold(
@@ -109,6 +112,41 @@ fun SettingsScreen(
)
}
}
+ item {
+ val block = viewModel
+ .getSettings(
+ booleanPreferencesKey(Constants.BLOCK_SCREENSHOTS_KEY),
+ false
+ ).collectAsState(
+ initial = false
+ )
+ BlockScreenshotsSettingsItem(
+ block.value
+ ){
+ viewModel.saveSettings(
+ booleanPreferencesKey(Constants.BLOCK_SCREENSHOTS_KEY),
+ it
+ )
+ }
+ }
+
+ item {
+ SettingsItemCard(
+ cornerRadius = 16.dp,
+ onClick = {
+ navController.navigate(Screen.ImportExportScreen.route)
+ }
+ ) {
+ Row {
+ Icon(painter = painterResource(id = R.drawable.ic_import_export), contentDescription = null)
+ Spacer(modifier = Modifier.width(8.dp))
+ Text(
+ text = stringResource(R.string.import_data),
+ style = MaterialTheme.typography.h6
+ )
+ }
+ }
+ }
item {
Text(
@@ -324,14 +362,24 @@ fun AppFontSettingsItem(
}
}
-@Preview
-@Composable
-fun ThemeItemPreview() {
- ThemeSettingsItem()
-}
-
-@Preview
@Composable
-fun StartUpItemPreview() {
- StartUpScreenSettingsItem(0)
+fun BlockScreenshotsSettingsItem(
+ block: Boolean,
+ onBlockClick: (Boolean) -> Unit = {}
+) {
+ SettingsItemCard(
+ cornerRadius = 16.dp,
+ onClick = {
+ onBlockClick(!block)
+ },
+ vPadding = 10.dp
+ ) {
+ Text(
+ text = stringResource(R.string.block_screenshots),
+ style = MaterialTheme.typography.h6
+ )
+ Switch(checked = block, onCheckedChange = {
+ onBlockClick(it)
+ })
+ }
}
\ No newline at end of file
diff --git a/app/src/main/java/com/mhss/app/mybrain/presentation/main/components/MainBottomBar.kt b/app/src/main/java/com/mhss/app/mybrain/presentation/main/components/MainBottomBar.kt
index cbc443f5..74eb48d6 100644
--- a/app/src/main/java/com/mhss/app/mybrain/presentation/main/components/MainBottomBar.kt
+++ b/app/src/main/java/com/mhss/app/mybrain/presentation/main/components/MainBottomBar.kt
@@ -28,9 +28,6 @@ fun MainBottomBar(
,
contentDescription = stringResource(it.title),
) },
- label = {
- Text(stringResource(it.title), style = MaterialTheme.typography.body2)
- },
selected = currentDestination?.route == it.route,
onClick = {
navController.navigate(it.route) {
diff --git a/app/src/main/java/com/mhss/app/mybrain/presentation/main/components/NavigationGraph.kt b/app/src/main/java/com/mhss/app/mybrain/presentation/main/components/NavigationGraph.kt
index b0f9fc34..4e1500b1 100644
--- a/app/src/main/java/com/mhss/app/mybrain/presentation/main/components/NavigationGraph.kt
+++ b/app/src/main/java/com/mhss/app/mybrain/presentation/main/components/NavigationGraph.kt
@@ -24,7 +24,7 @@ fun NavigationGraph(
SpacesScreen(mainNavController)
}
composable(Screen.SettingsScreen.route){
- SettingsScreen()
+ SettingsScreen(mainNavController)
}
}
}
\ No newline at end of file
diff --git a/app/src/main/java/com/mhss/app/mybrain/presentation/notes/NoteItem.kt b/app/src/main/java/com/mhss/app/mybrain/presentation/notes/NoteItem.kt
index 1fc7ec62..5ba1c6c4 100644
--- a/app/src/main/java/com/mhss/app/mybrain/presentation/notes/NoteItem.kt
+++ b/app/src/main/java/com/mhss/app/mybrain/presentation/notes/NoteItem.kt
@@ -30,7 +30,7 @@ fun NoteItem(
Card(
modifier = modifier,
shape = RoundedCornerShape(20.dp),
- elevation = 12.dp
+ elevation = 4.dp
) {
Column(
modifier = Modifier
@@ -61,7 +61,7 @@ fun NoteItem(
Spacer(Modifier.height(8.dp))
MarkdownText(
markdown = note.content,
- maxLines = 8,
+ maxLines = 14,
onClick = {onClick(note)},
fontSize = 12.sp
)
diff --git a/app/src/main/java/com/mhss/app/mybrain/presentation/notes/NotesScreen.kt b/app/src/main/java/com/mhss/app/mybrain/presentation/notes/NotesScreen.kt
index 299cd305..83c58177 100644
--- a/app/src/main/java/com/mhss/app/mybrain/presentation/notes/NotesScreen.kt
+++ b/app/src/main/java/com/mhss/app/mybrain/presentation/notes/NotesScreen.kt
@@ -11,6 +11,9 @@ import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.grid.LazyVerticalGrid
import androidx.compose.foundation.lazy.grid.items
import androidx.compose.foundation.lazy.items
+import androidx.compose.foundation.lazy.staggeredgrid.LazyVerticalStaggeredGrid
+import androidx.compose.foundation.lazy.staggeredgrid.StaggeredGridCells
+import androidx.compose.foundation.lazy.staggeredgrid.items
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.*
import androidx.compose.runtime.*
@@ -183,16 +186,10 @@ fun NotesScreen(
}
}
} else {
- LazyVerticalGrid(
- columns = GridCells.Adaptive(150.dp),
- verticalArrangement = Arrangement.spacedBy(12.dp),
+ LazyVerticalStaggeredGrid(
+ columns = StaggeredGridCells.Adaptive(150.dp),
horizontalArrangement = Arrangement.spacedBy(12.dp),
- contentPadding = PaddingValues(
- top = 12.dp,
- bottom = 24.dp,
- start = 12.dp,
- end = 12.dp
- )
+ contentPadding = PaddingValues(12.dp)
) {
items(uiState.notes) { note ->
key(note.id) {
@@ -209,7 +206,7 @@ fun NotesScreen(
)
)
},
- modifier = Modifier.animateItemPlacement().height(220.dp)
+ modifier = Modifier.padding(bottom = 12.dp)
)
}
}
diff --git a/app/src/main/java/com/mhss/app/mybrain/presentation/notes/NotesSearchScreen.kt b/app/src/main/java/com/mhss/app/mybrain/presentation/notes/NotesSearchScreen.kt
index 086fad18..4ddcb3ab 100644
--- a/app/src/main/java/com/mhss/app/mybrain/presentation/notes/NotesSearchScreen.kt
+++ b/app/src/main/java/com/mhss/app/mybrain/presentation/notes/NotesSearchScreen.kt
@@ -2,11 +2,11 @@ package com.mhss.app.mybrain.presentation.notes
import androidx.compose.foundation.ExperimentalFoundationApi
import androidx.compose.foundation.layout.*
-import androidx.compose.foundation.lazy.grid.GridCells
import androidx.compose.foundation.lazy.LazyColumn
-import androidx.compose.foundation.lazy.grid.LazyVerticalGrid
-import androidx.compose.foundation.lazy.grid.items
import androidx.compose.foundation.lazy.items
+import androidx.compose.foundation.lazy.staggeredgrid.LazyVerticalStaggeredGrid
+import androidx.compose.foundation.lazy.staggeredgrid.StaggeredGridCells
+import androidx.compose.foundation.lazy.staggeredgrid.items
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.OutlinedTextField
import androidx.compose.material.Text
@@ -73,9 +73,8 @@ fun NotesSearchScreen(
}
}
} else {
- LazyVerticalGrid(
- columns = GridCells.Adaptive(150.dp),
- verticalArrangement = Arrangement.spacedBy(12.dp),
+ LazyVerticalStaggeredGrid(
+ columns = StaggeredGridCells.Adaptive(150.dp),
horizontalArrangement = Arrangement.spacedBy(12.dp),
contentPadding = PaddingValues(12.dp)
){
@@ -94,7 +93,7 @@ fun NotesSearchScreen(
)
)
},
- modifier = Modifier.animateItemPlacement().height(220.dp)
+ modifier = Modifier.padding(bottom = 12.dp)
)
}
}
diff --git a/app/src/main/java/com/mhss/app/mybrain/presentation/settings/ImportExportScreen.kt b/app/src/main/java/com/mhss/app/mybrain/presentation/settings/ImportExportScreen.kt
new file mode 100644
index 00000000..c2ab51ee
--- /dev/null
+++ b/app/src/main/java/com/mhss/app/mybrain/presentation/settings/ImportExportScreen.kt
@@ -0,0 +1,217 @@
+package com.mhss.app.mybrain.presentation.settings
+
+import android.content.Intent
+import android.net.Uri
+import android.os.Build
+import android.provider.Settings
+import androidx.activity.compose.rememberLauncherForActivityResult
+import androidx.activity.result.contract.ActivityResultContracts
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.fillMaxSize
+import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.shape.RoundedCornerShape
+import androidx.compose.material.*
+import androidx.compose.runtime.*
+import androidx.compose.runtime.livedata.observeAsState
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.res.painterResource
+import androidx.compose.ui.res.stringResource
+import androidx.compose.ui.text.font.FontWeight
+import androidx.compose.ui.text.style.TextAlign
+import androidx.compose.ui.unit.dp
+import androidx.work.*
+import com.google.accompanist.permissions.ExperimentalPermissionsApi
+import com.google.accompanist.permissions.rememberPermissionState
+import com.mhss.app.mybrain.R
+import com.mhss.app.mybrain.app.MyBrainApplication
+import com.mhss.app.mybrain.data.backup.ExportWorker
+import com.mhss.app.mybrain.data.backup.ImportWorker
+import java.util.UUID
+
+@OptIn(ExperimentalPermissionsApi::class)
+@Composable
+fun ImportExportScreen() {
+
+ val writeStoragePermission = rememberPermissionState(
+ android.Manifest.permission.WRITE_EXTERNAL_STORAGE
+ )
+ val workManager = remember {
+ WorkManager.getInstance(MyBrainApplication.appContext)
+ }
+ val exportRequest by remember {
+ derivedStateOf {
+ OneTimeWorkRequestBuilder().build()
+ }
+ }
+ var importRequestId by remember {
+ mutableStateOf(null)
+ }
+
+ val exportWorkInfo = workManager.getWorkInfoByIdLiveData(exportRequest.id).observeAsState()
+ val importWorkInfo = if (importRequestId != null) {
+ workManager.getWorkInfoByIdLiveData(importRequestId!!).observeAsState()
+ } else {
+ null
+ }
+
+ val exportProgress = exportWorkInfo.value?.progress?.getInt("progress", 0)
+
+ val chooseDirectoryLauncher =
+ rememberLauncherForActivityResult(ActivityResultContracts.OpenDocument()) {
+ it?.let { uri ->
+ val importRequest =
+ OneTimeWorkRequestBuilder().setInputData(workDataOf("uri" to uri.toString()))
+ .build()
+ importRequestId = importRequest.id
+ workManager.enqueueUniqueWork("import", ExistingWorkPolicy.KEEP, importRequest)
+ }
+ }
+
+ Scaffold(
+ topBar = {
+ TopAppBar(
+ title = {
+ Text(
+ text = stringResource(R.string.export_import),
+ style = MaterialTheme.typography.h5.copy(fontWeight = FontWeight.Bold)
+ )
+ },
+ backgroundColor = MaterialTheme.colors.background,
+ elevation = 0.dp,
+ )
+ }
+ ) {
+ Column(Modifier.fillMaxSize()) {
+ Button(
+ onClick = {
+ if (Build.VERSION.SDK_INT < 29 && !writeStoragePermission.hasPermission) {
+ writeStoragePermission.launchPermissionRequest()
+ } else if (Build.VERSION.SDK_INT < 29 && !writeStoragePermission.shouldShowRationale) {
+ val intent = Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS)
+ intent.data = Uri.fromParts(
+ "package",
+ MyBrainApplication.appContext.packageName,
+ null
+ )
+ MyBrainApplication.appContext.startActivity(intent)
+ } else {
+ workManager.enqueueUniqueWork(
+ "export",
+ ExistingWorkPolicy.KEEP,
+ exportRequest
+ )
+ }
+ },
+ modifier = Modifier
+ .fillMaxWidth()
+ .align(Alignment.CenterHorizontally)
+ .padding(12.dp),
+ shape = RoundedCornerShape(8.dp)
+ ) {
+ if (Build.VERSION.SDK_INT >= 29 || writeStoragePermission.hasPermission)
+ Icon(painterResource(id = R.drawable.ic_export), null)
+ Text(
+ text = stringResource(
+ if (Build.VERSION.SDK_INT < 29 && !writeStoragePermission.hasPermission)
+ R.string.grant_permission_to_export
+ else
+ R.string.export
+ ),
+ style = MaterialTheme.typography.h6.copy(fontWeight = FontWeight.Bold),
+ modifier = Modifier.padding(12.dp)
+ )
+ }
+
+ if (exportProgress != null && exportProgress > 0) {
+ LinearProgressIndicator(
+ progress = exportProgress.toFloat() / 100,
+ modifier = Modifier
+ .fillMaxWidth()
+ .padding(12.dp)
+ )
+ Text(
+ text = "$exportProgress%",
+ modifier = Modifier.fillMaxWidth(),
+ style = MaterialTheme.typography.h6.copy(fontWeight = FontWeight.Bold),
+ textAlign = TextAlign.Center
+ )
+ }
+
+ if (exportWorkInfo.value?.outputData?.getBoolean("success", false) == true) {
+ Text(
+ text = stringResource(R.string.export_success),
+ modifier = Modifier.fillMaxWidth(),
+ style = MaterialTheme.typography.body2.copy(fontWeight = FontWeight.Bold),
+ textAlign = TextAlign.Center
+ )
+ } else if (exportWorkInfo.value?.state == WorkInfo.State.FAILED) {
+ Text(
+ text = stringResource(R.string.export_failed),
+ modifier = Modifier.fillMaxWidth(),
+ style = MaterialTheme.typography.body2.copy(fontWeight = FontWeight.Bold),
+ textAlign = TextAlign.Center,
+ color = MaterialTheme.colors.error
+ )
+ }
+
+ Button(
+ onClick = {
+ chooseDirectoryLauncher.launch(arrayOf("text/plain"))
+ },
+ modifier = Modifier
+ .fillMaxWidth()
+ .align(Alignment.CenterHorizontally)
+ .padding(12.dp),
+ shape = RoundedCornerShape(8.dp)
+ ) {
+ Icon(painterResource(id = R.drawable.ic_import), null)
+ Text(
+ text = stringResource(R.string.import_data),
+ style = MaterialTheme.typography.h6.copy(fontWeight = FontWeight.Bold),
+ modifier = Modifier.padding(12.dp)
+ )
+ }
+
+ if (importWorkInfo?.value?.outputData?.getString("success")?.isNotBlank() == true)
+ Text(
+ text = stringResource(
+ R.string.import_success,
+ importWorkInfo.value?.outputData?.getString("success") ?: ""
+ ),
+ modifier = Modifier
+ .fillMaxWidth()
+ .padding(12.dp),
+ style = MaterialTheme.typography.body2.copy(fontWeight = FontWeight.Bold),
+ textAlign = TextAlign.Start,
+ )
+
+
+ if (importWorkInfo?.value?.state == WorkInfo.State.FAILED) {
+ Text(
+ text = stringResource(R.string.import_failed),
+ modifier = Modifier
+ .fillMaxWidth()
+ .padding(12.dp),
+ style = MaterialTheme.typography.body2.copy(fontWeight = FontWeight.Bold),
+ textAlign = TextAlign.Center,
+ color = MaterialTheme.colors.error
+ )
+ }
+ if (importWorkInfo?.value?.state == WorkInfo.State.RUNNING){
+ CircularProgressIndicator(
+ Modifier
+ .align(Alignment.CenterHorizontally)
+ .padding(12.dp))
+ Text(text = stringResource(R.string.importing),
+ Modifier
+ .align(Alignment.CenterHorizontally)
+ .padding(8.dp),
+ style = MaterialTheme.typography.body2.copy(fontWeight = FontWeight.Bold),
+ textAlign = TextAlign.Center)
+ }
+
+ }
+ }
+}
diff --git a/app/src/main/java/com/mhss/app/mybrain/presentation/settings/SettingsItemCard.kt b/app/src/main/java/com/mhss/app/mybrain/presentation/settings/SettingsItemCard.kt
index a0aca6b7..3caf7f81 100644
--- a/app/src/main/java/com/mhss/app/mybrain/presentation/settings/SettingsItemCard.kt
+++ b/app/src/main/java/com/mhss/app/mybrain/presentation/settings/SettingsItemCard.kt
@@ -14,6 +14,8 @@ import androidx.compose.ui.unit.dp
fun SettingsItemCard(
modifier: Modifier = Modifier,
cornerRadius: Dp = 25.dp,
+ hPadding: Dp = 12.dp,
+ vPadding: Dp = 16.dp,
onClick: () -> Unit = {},
content: @Composable RowScope.() -> Unit,
) {
@@ -28,7 +30,7 @@ fun SettingsItemCard(
Modifier
.fillMaxWidth()
.clickable { onClick() }
- .padding(horizontal = 12.dp, vertical = 16.dp),
+ .padding(horizontal = hPadding, vertical = vPadding),
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.SpaceBetween,
content = content
diff --git a/app/src/main/java/com/mhss/app/mybrain/presentation/tasks/TaskWidgetItem.kt b/app/src/main/java/com/mhss/app/mybrain/presentation/tasks/TaskWidgetItem.kt
index 8bf160d7..ca6d09c0 100644
--- a/app/src/main/java/com/mhss/app/mybrain/presentation/tasks/TaskWidgetItem.kt
+++ b/app/src/main/java/com/mhss/app/mybrain/presentation/tasks/TaskWidgetItem.kt
@@ -32,22 +32,29 @@ fun TaskWidgetItem(
task: Task
) {
Box(
- GlanceModifier
- .padding(bottom = 3.dp)
- .clickable(
- onClick = actionRunCallback(
- parameters = actionParametersOf(
- taskId to task.id
- )
- )
- )
+ GlanceModifier.padding(bottom = 3.dp)
) {
Column(
GlanceModifier
.background(ImageProvider(R.drawable.small_item_rounded_corner_shape))
.padding(10.dp)
+ .clickable(
+ actionRunCallback(
+ parameters = actionParametersOf(
+ taskId to task.id
+ )
+ )
+ )
) {
- Row(GlanceModifier.fillMaxWidth(), verticalAlignment = Alignment.CenterVertically) {
+ Row(GlanceModifier
+ .fillMaxWidth()
+ .clickable(
+ actionRunCallback(
+ parameters = actionParametersOf(
+ taskId to task.id
+ )
+ ))
+ , verticalAlignment = Alignment.CenterVertically) {
TaskWidgetCheckBox(
isComplete = task.isCompleted,
task.priority.toPriority().color,
@@ -68,6 +75,12 @@ fun TaskWidgetItem(
textDecoration = if (task.isCompleted) TextDecoration.LineThrough else TextDecoration.None
),
maxLines = 2,
+ modifier = GlanceModifier.clickable(actionRunCallback(
+ parameters = actionParametersOf(
+ taskId to task.id,
+ completed to !task.isCompleted
+ )
+ ))
)
}
if (task.dueDate != 0L) {
diff --git a/app/src/main/java/com/mhss/app/mybrain/presentation/tasks/TasksHomeScreenWidget.kt b/app/src/main/java/com/mhss/app/mybrain/presentation/tasks/TasksHomeScreenWidget.kt
index fc7dff9a..5038651c 100644
--- a/app/src/main/java/com/mhss/app/mybrain/presentation/tasks/TasksHomeScreenWidget.kt
+++ b/app/src/main/java/com/mhss/app/mybrain/presentation/tasks/TasksHomeScreenWidget.kt
@@ -33,9 +33,7 @@ fun TasksHomeScreenWidget(
.cornerRadius(25.dp)
) {
Column(
- modifier = GlanceModifier
- .clickable(onClick = actionRunCallback())
- .padding(8.dp)
+ modifier = GlanceModifier.padding(8.dp)
) {
Row(
GlanceModifier.fillMaxWidth(),
@@ -49,20 +47,24 @@ fun TasksHomeScreenWidget(
fontWeight = FontWeight.Bold,
fontSize = 16.sp
),
- modifier = GlanceModifier.padding(horizontal = 8.dp),
+ modifier = GlanceModifier
+ .padding(horizontal = 8.dp)
+ .clickable(actionRunCallback()),
)
Row(
- modifier = GlanceModifier.fillMaxWidth().padding(horizontal = 8.dp),
+ modifier = GlanceModifier
+ .fillMaxWidth()
+ .padding(horizontal = 8.dp)
+ .clickable(actionRunCallback()),
horizontalAlignment = Alignment.End
) {
- Button(
- text = "",
+ Image(
+ provider = ImageProvider(R.drawable.ic_add),
modifier = GlanceModifier
.size(22.dp)
- .background(ImageProvider(R.drawable.ic_add))
- .padding(8.dp)
+ .clickable(actionRunCallback())
,
- onClick = actionRunCallback()
+ contentDescription = "Add task"
)
}
}
diff --git a/app/src/main/java/com/mhss/app/mybrain/presentation/tasks/TasksViewModel.kt b/app/src/main/java/com/mhss/app/mybrain/presentation/tasks/TasksViewModel.kt
index 6dd78143..58b4082a 100644
--- a/app/src/main/java/com/mhss/app/mybrain/presentation/tasks/TasksViewModel.kt
+++ b/app/src/main/java/com/mhss/app/mybrain/presentation/tasks/TasksViewModel.kt
@@ -33,6 +33,7 @@ class TasksViewModel @Inject constructor(
private val getAllTasks: GetAllTasksUseCase,
private val getTaskUseCase: GetTaskByIdUseCase,
private val updateTask: UpdateTaskUseCase,
+ private val completeTask: UpdateTaskCompletedUseCase,
getSettings: GetSettingsUseCase,
private val saveSettings: SaveSettingsUseCase,
private val addAlarm: AddAlarmUseCase,
@@ -85,11 +86,7 @@ class TasksViewModel @Inject constructor(
tasksUiState = tasksUiState.copy(error = getString(R.string.error_empty_title))
}
is TaskEvent.CompleteTask -> viewModelScope.launch {
- updateTask(
- event.task.copy(
- isCompleted = event.complete,
- )
- )
+ completeTask(event.task.id, event.complete)
if (event.complete)
deleteAlarm(event.task.id)
}
diff --git a/app/src/main/java/com/mhss/app/mybrain/presentation/util/Screen.kt b/app/src/main/java/com/mhss/app/mybrain/presentation/util/Screen.kt
index 7ec874f0..1b62f3d9 100644
--- a/app/src/main/java/com/mhss/app/mybrain/presentation/util/Screen.kt
+++ b/app/src/main/java/com/mhss/app/mybrain/presentation/util/Screen.kt
@@ -23,4 +23,5 @@ sealed class Screen(val route: String) {
object CalendarScreen : Screen("calendar_screen")
object CalendarEventDetailsScreen : Screen("calendar_event_details_screen/{${Constants.CALENDAR_EVENT_ARG}}")
object NoteFolderDetailsScreen : Screen("note_folder_details_screen/{${Constants.FOLDER_ID}}")
+ object ImportExportScreen : Screen("import_export_screen")
}
\ No newline at end of file
diff --git a/app/src/main/java/com/mhss/app/mybrain/util/BackupUtil.kt b/app/src/main/java/com/mhss/app/mybrain/util/BackupUtil.kt
new file mode 100644
index 00000000..759cc901
--- /dev/null
+++ b/app/src/main/java/com/mhss/app/mybrain/util/BackupUtil.kt
@@ -0,0 +1,46 @@
+package com.mhss.app.mybrain.util
+
+import com.squareup.moshi.*
+import com.squareup.moshi.kotlin.reflect.KotlinJsonAdapterFactory
+import java.util.*
+
+object BackupUtil {
+
+ inline fun List.toJson(): String{
+ val moshi = Moshi.Builder().add(UUIDAdapter()).addLast(KotlinJsonAdapterFactory()).build()
+ val adapter: JsonAdapter> = moshi.adapter(Types.newParameterizedType(List::class.java, T::class.java))
+ return adapter.toJson(this)
+ }
+
+ inline fun T.toJson(): String{
+ val moshi = Moshi.Builder().add(UUIDAdapter()).addLast(KotlinJsonAdapterFactory()).build()
+ val adapter: JsonAdapter = moshi.adapter(T::class.java)
+ return adapter.toJson(this)
+ }
+
+ inline fun String.objectFromJson(): T?{
+ val moshi = Moshi.Builder().add(UUIDAdapter()).addLast(KotlinJsonAdapterFactory()).build()
+ val adapter: JsonAdapter = moshi.adapter(T::class.java)
+ return adapter.fromJson(this)
+ }
+
+ inline fun String.listFromJson(): List?{
+ val moshi = Moshi.Builder().add(UUIDAdapter()).addLast(KotlinJsonAdapterFactory()).build()
+ val adapter: JsonAdapter> = moshi.adapter(Types.newParameterizedType(List::class.java, T::class.java))
+ return adapter.fromJson(this)
+ }
+
+
+}
+
+class UUIDAdapter {
+ @FromJson
+ fun fromJson(json: String): UUID {
+ return UUID.fromString(json)
+ }
+
+ @ToJson
+ fun toJson(uuid: UUID): String {
+ return uuid.toString()
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/mhss/app/mybrain/util/Constants.kt b/app/src/main/java/com/mhss/app/mybrain/util/Constants.kt
index 490483b1..3ded569c 100644
--- a/app/src/main/java/com/mhss/app/mybrain/util/Constants.kt
+++ b/app/src/main/java/com/mhss/app/mybrain/util/Constants.kt
@@ -20,6 +20,7 @@ object Constants {
const val DIARY_ORDER_KEY = "diary_order"
const val EXCLUDED_CALENDARS_KEY = "excluded_calendars"
const val APP_FONT_KEY = "app_font"
+ const val BLOCK_SCREENSHOTS_KEY = "block_screen_shots"
// Navigation
const val TASK_ID_ARG = "task_id"
@@ -41,4 +42,11 @@ object Constants {
const val GITHUB_ISSUES_LINK = "https://github.com/mhss1/ByBrain/issues"
const val GITHUB_RELEASES_LINK = "https://github.com/mhss1/ByBrain/releases"
+ // Backup
+ const val EXPORT_DIR = "MyBrain Export"
+ const val BACKUP_NOTES_FILE_NAME = "mybrain_notes.txt"
+ const val BACKUP_TASKS_FILE_NAME = "mybrain_tasks.txt"
+ const val BACKUP_DIARY_FILE_NAME = "mybrain_diary.txt"
+ const val BACKUP_BOOKMARKS_FILE_NAME = "mybrain_bookmarks.txt"
+
}
\ No newline at end of file
diff --git a/app/src/main/java/com/mhss/app/mybrain/util/calendar/CalendarUtil.kt b/app/src/main/java/com/mhss/app/mybrain/util/calendar/CalendarUtil.kt
index 98d5b2b3..1b80b278 100644
--- a/app/src/main/java/com/mhss/app/mybrain/util/calendar/CalendarUtil.kt
+++ b/app/src/main/java/com/mhss/app/mybrain/util/calendar/CalendarUtil.kt
@@ -26,8 +26,8 @@ fun CalendarEvent.getEventDuration(): String {
fun String.extractEndFromDuration(start: Long): Long {
return try {
- val duration = this.substring(1, this.length - 1)
- start + duration.toLong()
+ val duration = this.substring(1, this.length - 1).toLong() * 1000
+ start + duration
}catch (e: Exception) {
start
}
diff --git a/app/src/main/java/com/mhss/app/mybrain/util/date/DateUtils.kt b/app/src/main/java/com/mhss/app/mybrain/util/date/DateUtils.kt
index 830c404f..ec633b1d 100644
--- a/app/src/main/java/com/mhss/app/mybrain/util/date/DateUtils.kt
+++ b/app/src/main/java/com/mhss/app/mybrain/util/date/DateUtils.kt
@@ -21,8 +21,8 @@ fun Long.fullDate(): String {
return sdf.format(this)
}
-fun Long.formatDay(): String {
- val sdf = SimpleDateFormat("EEEE d", Locale.getDefault())
+fun Long.formatDateForMapping(): String {
+ val sdf = SimpleDateFormat("EEEE d, MMM yyy", Locale.getDefault())
return sdf.format(this)
}
diff --git a/app/src/main/res/drawable/ic_export.xml b/app/src/main/res/drawable/ic_export.xml
new file mode 100644
index 00000000..46d5d587
--- /dev/null
+++ b/app/src/main/res/drawable/ic_export.xml
@@ -0,0 +1,5 @@
+
+
+
diff --git a/app/src/main/res/drawable/ic_import.xml b/app/src/main/res/drawable/ic_import.xml
new file mode 100644
index 00000000..dcfb7840
--- /dev/null
+++ b/app/src/main/res/drawable/ic_import.xml
@@ -0,0 +1,5 @@
+
+
+
diff --git a/app/src/main/res/drawable/ic_import_export.xml b/app/src/main/res/drawable/ic_import_export.xml
new file mode 100644
index 00000000..c40dc3b7
--- /dev/null
+++ b/app/src/main/res/drawable/ic_import_export.xml
@@ -0,0 +1,5 @@
+
+
+
diff --git a/app/src/main/res/values-ar/strings.xml b/app/src/main/res/values-ar/strings.xml
index cb6399b8..0bd5ebf7 100644
--- a/app/src/main/res/values-ar/strings.xml
+++ b/app/src/main/res/values-ar/strings.xml
@@ -56,8 +56,6 @@
هل أنت متأكد من حذف هذه العلامة المرجعية؟
هل أنت متأكد من حذف هذه من اليوميات؟
إلغاء
- الدعم بواسطة :
- شكراً على دعمك ❤
ليس لديك أي مهام\n أظغط على زر + لإضافة مهام جديدة \n أو \n بواسطة الإختصار من قائمة الاعدادات السريعة بجهازك
ليس لديك أي ملاحظات.\n اضغط على + لإضافة ملاحظة جديدة
ليس لديك أي يوميات.\n اضغط على + لإضافة يومية جديدة
@@ -151,4 +149,14 @@
هل انت متأكد من حذف الملف و كل محنوياته؟
حفظ
تعديل الملف
+ منع لقطات الشاشة
+ تصدير\استيراد البيانات
+ تصدير
+ تم تصدير البيانات الى \"Documents/MyBrain Export\"
+ حدث خطأ أثناء التصدير
+ استيراد البيانات
+ تم تصدير %1$s
+ حدث خطأ أثناء الاستيراد. تأكد من عدم نغيير اسم الملف او المحتوى
+ منح اذن التخزين للتصدير
+ يتم الاستيراد....
\ No newline at end of file
diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml
new file mode 100644
index 00000000..fbb50aea
--- /dev/null
+++ b/app/src/main/res/values-de/strings.xml
@@ -0,0 +1,161 @@
+
+ My Brain
+
+ Benachrichtigungskanal zum Senden von Aufgabenerinnerungen
+ Erinnerungen
+ Fertig
+ Dashboard
+ Einstellungen
+ Übersicht
+ App Theme
+ Helles Theme
+ Dunkles Theme
+ Auto
+ Startbildschirm
+ Über
+ App Version
+ Projekt auf GitHub
+ Datenschutzrichtlinien
+ Produkt
+ Notizen
+ Aufgaben
+ Tagebuch
+ Lesezeichen
+ Kalender
+ Aufgabe hinzufügen
+ Aufgabe zu My Brain hinzufügen
+ Suche
+ Titel
+ Unteraugabe löschen
+ Unteraufgabe hinzufügen
+ Beschreibung
+ Fordere ein Feature an / Melde einen Fehler
+ Niedrig
+ Mittel
+ Hoch
+ Fälligkeitsdatum
+ Titel darf nicht leer sein
+ Priorität
+ Sortieren nach
+ Alphabetisch
+ Erstellungsdatum
+ Änderungsdatum
+ Aufsteigend
+ Absteigend
+ Komplette Aufgabe anzeigen
+ Aufgabe suchen
+ Aufgabe speichern
+ Aufgabe löschen
+ Aufgabe löschen?
+ Notiz löschen?
+ Lesezeichen löschen?
+ Eintrag löschen?
+ Diese Aufgabe wirklich löschen?: \n \"%1$s\""
+ Diese Notiz wirklich löschen?: \n \"%1$s\""
+ Dieses Lesezeichen wirklich löschen?:""
+ Diesen Eintrag wirklich löschen?:""
+ Abbrechen
+ Du hast noch keine Aufgaben\n Klicke auf den + Button um eine neue\n Aufgabe oder \nin dem du den Shortcut in den\n Schnelleinstellungen benutzt
+ Du hast noch keine Notizen\n Klicke auf den + Butten um eine neue Notiz hinzuzufügen
+ Du hast noch keine Einträge\n Klicke auf den + Button um einen neuen Eintrag hinzuzufügen
+ Du hast noch keine Lesezeichen\n Klicke auf den + Button um ein neues\n Lesezeichen hinzuzufügen\n oder \nnutze die Teilen funktion deines Browsers
+ Projekt Fahrplan
+ Liste
+ Gitter
+ Notizinhalt (unterstützt Markdown)
+ Notiz löschen
+ Notiz darf nicht leer sein
+ Notiz anpinnen
+ Lesemodus
+ Zeige als
+ Suche nach Titel oder Inhalt
+ Füge Notiz hinzu
+ Lesezeichen Link
+ Zu Aufgaben hinzufügen
+ Lesezeichen erfolgreich gespeichert
+ Ungültige URL
+ füge Lesezeichen hinzu
+ Link öffnen
+ Lesezeichen suchen
+ Lesezeichen löschen
+ URL
+ Änderungen verwerfen
+ Eintrag hinzufügen
+ Unglaublich
+ Gut
+ Okay
+ Schlecht
+ Schrecklich
+ Eintrag löschen
+ Inhalt
+ Eintrag speichern
+ Tagebuch suchen
+ Stimmung
+ %1$s - %2$s at %3$s
+ %1$s - %2$s
+ Ganztags
+ Für dieses Feature werden Leserechte für deinen Kalender benötigt.\nBitte erteile deine Erlaubnis
+ Für dieses Feature werden Schreibrechte für deinen Kalender benötigt.\nBitte erteile deine Erlaubnis
+ Erlaubnis erteilen
+ Gehe zu Einstellungen
+ Ereignis hinzufügen
+ anzuzeigende Kalender:
+ Zu Aufgaben hinzugefügt
+ Tagebuch Diagramm
+ Deine Stimmung in diesem Monat
+ Deine Stimmung in diesem Jahr
+ %1$d%%
+ Stimmungs Tendenz
+ Stimmungs Zusammenfassung
+ "Deine Stimmung war "
+ " die meiste Zeit "
+ In den letzten 30 Tagen
+ Im letzten Jahr
+ Keine Daten bis jetzt
+ Keine Ereignis bis jetzt
+ Aufgaben Anzahl
+ Du bist fertig
+ mit den Aufgaben der letzten Woche
+ Keine Aufgaben bis jetzt
+ Lade…
+ Drücke den Aktualisieren Button wenn du die Erlaubnis bereits erteilt hast
+ Donnerstag 30
+ Sonntag 5
+ Abendessen mit Ali
+ CS Vortrag
+ Zahnarztbesuch
+ Lebensmittel kaufen
+ Mama anrufen
+ App Schriftart
+ Systemstandard
+ Ereignis löschen
+ Standort
+ Nicht wiederholen
+ Jeden Tag
+ Jede Woche
+ Jeden Monat
+ Jedes Jahr
+ Ereignis sollte nicht in der Vergangenheit liegen
+ Ereignis löschen?
+ Dieses Ereignis wirklich löschen?
+ Ordner
+ Ordner erstellen
+ Ordner existiert bereits
+ Name
+ Ordner wechseln
+ Keine
+ Ordner löschen
+ Bist du dir sicher das du diesen Ordner und dessen Inhalt löschen möchtest?
+ Speichern
+ Ordner bearbeiten
+ Bildschirmfotos blockieren
+ Export/Import
+ Export
+ Successfully exported data to \"Documents/MyBrain Export\"
+ Something went wrong while exporting
+ Import data
+ Successfully imported %1$s
+ Something went wrong while importing. make sure that the file name and content are not corrupted
+ Grant permission to export
+ Importing....
+
\ No newline at end of file
diff --git a/app/src/main/res/values-hi/strings.xml b/app/src/main/res/values-hi/strings.xml
index 383c95e8..4e2affd3 100644
--- a/app/src/main/res/values-hi/strings.xml
+++ b/app/src/main/res/values-hi/strings.xml
@@ -52,8 +52,6 @@
क्या आप वाकई इस बुकमार्क को हटाना चाहते हैं
क्या आप वाकई इस एंट्री को हटाना चाहते हैं
रद्द करे
- समर्थन करे:
- आपके समर्थन के लिए धन्यवाद ❤
प्रोजेक्ट रोडमैप
सूची
ग्रिड
@@ -150,4 +148,14 @@
क्या आप वाकई इस फ़ोल्डर और इसकी सभी सामग्री को हटाना चाहते हैं?
बचाना
फोल्डर संपादित करें
+ Block screenshots
+ Export/Import
+ Export
+ Successfully exported data to \"Documents/MyBrain Export\"
+ Something went wrong while exporting
+ Import data
+ Successfully imported %1$s
+ Something went wrong while importing. make sure that the file name and content are not corrupted
+ Grant permission to export
+ Importing....
\ No newline at end of file
diff --git a/app/src/main/res/values-pl/strings.xml b/app/src/main/res/values-pl/strings.xml
index ccd44ac3..a5a2307c 100644
--- a/app/src/main/res/values-pl/strings.xml
+++ b/app/src/main/res/values-pl/strings.xml
@@ -56,8 +56,6 @@
Czy na pewno chcesz usunąć tą zakładkę""
Czy na pewno chcesz usunąć ten wpis""
Anuluj
- Możesz nas wesprzeć :
- Dziękujemy za wsparcie ❤
Nie dodano żadnych zadań\nAby dodać nowe Zadanie kliknij przycisk +\n lub \nużyj skrótu na pasku szybkich ustawień
Nie dodano żadnych notatek\n Aby dodać nową Notatkę kliknij przycisk +
Nie dodano żadnych wpisów\n Aby dodać nowy wpis kliknij przycisk +
@@ -151,4 +149,14 @@
Czy
Zapisz
Edytuj folder
+ Block screenshots
+ Export/Import
+ Export
+ Successfully exported data to \"Documents/MyBrain Export\"
+ Something went wrong while exporting
+ Import data
+ Successfully imported %1$s
+ Something went wrong while importing. make sure that the file name and content are not corrupted
+ Grant permission to export
+ Importing....
\ No newline at end of file
diff --git a/app/src/main/res/values-pt-rBR/strings.xml b/app/src/main/res/values-pt-rBR/strings.xml
new file mode 100644
index 00000000..9585c4bc
--- /dev/null
+++ b/app/src/main/res/values-pt-rBR/strings.xml
@@ -0,0 +1,161 @@
+
+ My Brain
+
+ Canal de notificação para enviar lembretes de tarefas
+ Lembretes
+ Concluído
+ Dashboard
+ Configurações
+ Spaces
+ Temas
+ Tema Claro
+ Tema Escuro
+ Automático
+ Tela de início
+ Sobre
+ Versão
+ Projeto no GitHub
+ Política de Privacidade
+ Produto
+ Notas
+ Tarefas
+ Diário
+ Favoritos
+ Agenda
+ Adicionar tarefa
+ Adicionar tarefa ao My Brain
+ Procurar
+ Título
+ Remover subtarefa
+ Adicionar subtarefa
+ Descrição
+ Solicite um recurso / Reporte um erro
+ Baixa
+ Média
+ Alta
+ Válido até
+ O título não pode estar vázio
+ Prioridade
+ Ordenar por
+ Alfabética
+ Data de criação
+ Data de modificação
+ Crescente
+ Decrescente
+ Mostrar tarefas concluídas
+ Procurar tarefas
+ Salvar Tarefa
+ Remover Tarefa
+ Remover Tarefa?
+ Remover Nota?
+ Remover Favorito?
+ Remover Entrada?
+ Você deseja realmente remover a Tarefa: \n \"%1$s\""
+ Você deseja realmente remover a Nota: \n \"%1$s\""
+ Você deseja realmente remover este bookmark""
+ Você deseja realmente remover esta entrada""
+ Cancelar
+ Você não tem nenhuma tarefa\n Clique no botão + para adicionar uma nova Tarefa\n ou \nuse o atalho no menu das configurações rápidas
+ Você não tem nenhuma nota\n Clique no botão + para adicionar uma nova Nota
+ Você não tem nenhuma entrada\n Clique no botão + para adicionar uma nova entrada
+ Você não tem nenhum favorito\n Clique no botão + para adicionar um novo favorito\n ou \nuse a opção de compartilhar de qualquer navegador
+ Metas do Projeto
+ Lista
+ Grade
+ Conteúdo da nota (suporta markdown)
+ Remover Nota
+ A Nota não pode estar vázia
+ Fixar nota
+ Modo de leitura
+ Ver como
+ Procurar por título ou conteúdo
+ Adicionar nota
+ Salvar link como favorito
+ Adicionar a tarefas
+ Favorito salvo com sucesso
+ URL Inválida
+ Adicionar favorito
+ Abrir link
+ Pesquisar Favoritos
+ Remover Favoritos
+ URL
+ Cancelar mudanças
+ Adicionar entrada
+ Ótimo
+ Bom
+ Regular
+ Mau
+ Péssimo
+ Remover entrada
+ Conteúdo
+ Salvar entrada
+ Pesquisar diário
+ Humor
+ %1$s - %2$s às %3$s
+ %1$s - %2$s
+ O dia todo
+ Permissão de Leitura na Agenda necessária para que este recurso esteja disponível.\nPor favor, conceda a permissão
+ Permissão de Escrita na Agenda necessária para que este recurso esteja disponível.\nPor favor, conceda a permissão
+ Conceda a permissão
+ Ir para configurações
+ Adicionar evento
+ Incluir agendas :
+ Adicionado a tarefas
+ Gráfico do Diário
+ Seu humor durante o mês
+ Seu humor durante o ano
+ %1$d%%
+ Humor
+ Humor
+ "Seu humor estava "
+ " na maior parte do tempo "
+ Últimos 30 dias
+ Último ano
+ Sem dados ainda
+ Sem eventos ainda
+ Tarefas
+ Você concluiu
+ das Tarefas na última semana
+ Sem tarefas ainda
+ Carregando…
+ Se você já concedeu a permissão, clique no botão atualizar
+ Quinta 30
+ Domingo 5
+ Jantar com o Ali
+ Aula de Computação
+ Consulta dentista
+ Fazer compras
+ Ligar para mamãe
+ Fonte
+ Padrão do Sistema
+ Remover evento
+ Localização
+ Não repetir
+ Todo dia
+ Toda semana
+ Todo mês
+ Todo ano
+ O Evento não deve ser no passado
+ Remover Evento?
+ Você tem certeza que deseja remover o evento?
+ Pastas
+ Criar pasta
+ A pasta já existe
+ Nome
+ Mudar pasta
+ Nenhum
+ Remover pasta
+ Você tem certeza que deseja remover esta pasta e todo o seu conteúdo?
+ Salvar
+ Editar pasta
+ Block screenshots
+ Export/Import
+ Export
+ Successfully exported data to \"Documents/MyBrain Export\"
+ Something went wrong while exporting
+ Import data
+ Successfully imported %1$s
+ Something went wrong while importing. make sure that the file name and content are not corrupted
+ Grant permission to export
+ Importing....
+
diff --git a/app/src/main/res/values-ro/strings.xml b/app/src/main/res/values-ro/strings.xml
new file mode 100644
index 00000000..b10d4c19
--- /dev/null
+++ b/app/src/main/res/values-ro/strings.xml
@@ -0,0 +1,161 @@
+
+ My Brain
+
+ Canal de notificare pentru trimiterea de notificări de reamintire a sarcinilor
+ Mementouri
+ Complet
+ Panou
+ Setări
+ Spații
+ Tema aplicației
+ Temă luminoasă
+ Temă întunecată
+ Automat
+ Ecran de pornire
+ Despre
+ Versiunea aplicației
+ Proiectul pe GitHub
+ Politica de confidențialitate
+ Produs
+ Note
+ Sarcini
+ Jurnal
+ Marcaj
+ Calendar
+ Adaugă sarcină
+ Adaugă sarcina la My Brain
+ Caută
+ Titlu
+ Șterge sub-sarcină
+ Adaugă sub-sarcină
+ Descriere
+ Solicită o funcție / Raportează un bug
+ Scăzută
+ Medie
+ Înaltă
+ Data limită
+ Titlul nu poate fi gol
+ Prioritate
+ Ordonează după
+ Alfabetic
+ Data creării
+ Data modificării
+ Crescător
+ Descrescător
+ Arată sarcinile completate
+ Caută sarcini
+ Salvează sarcina
+ Șterge sarcina
+ Ștergeți sarcina?
+ Ștergeți nota?
+ Ștergeți marcajul?
+ Ștergeți intrarea?
+ Sigur dorești ștergerea sarcinii: \n \"%1$s\""?
+ Sigur dorești ștergerea notei: \n \"%1$s\""?
+ Sigur dorești ștergerea marcajului""?
+ Sigur dorești ștergerea acestei intrări""?
+ Anulare
+ Nu aveți nicio sarcină\n Faceți clic pe butonul + pentru a adăuga o nouă sarcină\n sau \nprin utilizarea comenzii rapide din meniul de setări rapide
+ Nu aveți nicio notă\n Faceți clic pe butonul + pentru a adăuga o nouă notă
+ Nu aveți nicio intrare\n Faceți clic pe butonul + pentru a adăuga o nouă intrare
+ Nu aveți niciun marcaj\n Faceți clic pe butonul + pentru a adăuga un nou marcaj\n sau \nprin utilizarea opțiunii de distribuire din orice browser
+ Harta proiectului
+ Listă
+ Grilă
+ Conținutul notei (suportă markdown)
+ Șterge nota
+ Nota nu poate fi goală
+ Fixează nota
+ Modul de citire
+ Vezi ca
+ Căutare după titlu sau conținut
+ Adaugă notă
+ Marchează link-ul
+ Adaugă la sarcini
+ Marcaj salvat cu succes
+ Adresă URL invalidă
+ Adaugă marcaj
+ Deschide link
+ Caută marcaje
+ Șterge marcajul
+ Adresă URL
+ Anulează modificările
+ Adaugă intrare
+ Minunat
+ Bun
+ Okay
+ Rău
+ Teribil
+ Șterge intrarea
+ Conținut
+ Salvează intrarea
+ Caută în Jurnal
+ Dispoziție
+ %1$s - %2$s at %3$s
+ %1$s - %2$s
+ Toată ziua
+ Este necesară permisiunea de citire a calendarului pentru ca această funcție să fie disponibilă.\nTe rog să acorzi permisiunea
+ Este necesară permisiunea de scriere a calendarului pentru ca această funcție să fie disponibilă.\nTe rog să acorzi permisiunea
+ Acordă permisiunea
+ Accesează setările
+ Adaugă eveniment
+ Include calendarele:
+ Adăugat la sarcini
+ Graficul jurnalului
+ Dispoziția ta pe parcursul lunii
+ Dispoziția ta pe parcursul anului
+ %1$d%%
+ Fluxul dispoziției
+ Rezumatul dispoziției
+ "Dispoziția ta a fost "
+ " majoritatea timpului "
+ Ultimele 30 de zile
+ Anul trecut
+ Nu există încă date
+ Niciun eveniment încă
+ Rezumatul sarcinilor
+ Ai finalizat
+ de sarcini în ultima săptămână
+ Nicio sarcină încă
+ Încărcare…
+ Faceți clic pe butonul de reîmprospătare dacă ați acordat deja permisiunea
+ Joi 30
+ Duminică 5
+ Cina cu Ali
+ Curs CS
+ Vizitează dentistul
+ Cumpără alimente
+ Sun-o pe mama
+ Fontul aplicației
+ Implicit al sistemului
+ Șterge evenimentul
+ Locație
+ Nu se repetă
+ În fiecare zi
+ În fiecare săptămână
+ În fiecare lună
+ În fiecare an
+ Evenimentul nu ar trebui să fie în trecut
+ Ștergeți evenimentul?
+ Sigur dorești ștergerea acestui eveniment?
+ Dosare
+ Creează un dosar
+ Dosarul există deja
+ Nume
+ Schimbă dosarul
+ None
+ Șterge dosarul
+ Sunteți sigur că doriți să ștergeți acest dosar și tot conținutul său?
+ Save
+ Editează dosarul
+ Block screenshots
+ Export/Import
+ Export
+ Successfully exported data to \"Documents/MyBrain Export\"
+ Something went wrong while exporting
+ Import data
+ Successfully imported %1$s
+ Something went wrong while importing. make sure that the file name and content are not corrupted
+ Grant permission to export
+ Importing....
+
\ No newline at end of file
diff --git a/app/src/main/res/values-ru/strings.xml b/app/src/main/res/values-ru/strings.xml
index a76bc5f7..b438b58f 100644
--- a/app/src/main/res/values-ru/strings.xml
+++ b/app/src/main/res/values-ru/strings.xml
@@ -55,8 +55,6 @@
Вы уверены, что хотите удалить эту закладку?""
Вы уверены, что хотите удалить эту запись?""
Отмена
- Поддержать с помощью
- Спасибо за поддержку ❤
У вас нет задач\nНажмите на +, чтобы добавить новую задачу\nили используйте кнопку\nв меню быстрого доступа
У вас нет заметок\nНажмите на +, чтобы добавить новую заметку
У вас нет записей\nНажмите на +, чтобы добавить новую запись
@@ -150,4 +148,14 @@
Вы уверены, что хотите удалить папку и всё её содержимое?
Сохранить
Редактировать папку
+ Block screenshots
+ Export/Import
+ Export
+ Successfully exported data to \"Documents/MyBrain Export\"
+ Something went wrong while exporting
+ Import data
+ Successfully imported %1$s
+ Something went wrong while importing. make sure that the file name and content are not corrupted
+ Grant permission to export
+ Importing....
\ No newline at end of file
diff --git a/app/src/main/res/values-zh-rCN/strings.xml b/app/src/main/res/values-zh-rCN/strings.xml
index a077e575..3d24683b 100644
--- a/app/src/main/res/values-zh-rCN/strings.xml
+++ b/app/src/main/res/values-zh-rCN/strings.xml
@@ -55,8 +55,6 @@
你确定要删除这个书签吗?
你确定要删除这篇日记吗?
取消
- 可选方式:
- 感谢你的支持 ❤
目前没有待办事项\n 点击+按钮创建待办事项\n 或使用快速设置菜单中的快捷方式
目前没有笔记\n 点击+按钮创建笔记
目前没有日记\n 点击+按钮创建日记
@@ -150,4 +148,14 @@
你确定要删除这个文件夹以及其中的内容吗?
保存
编辑文件夹
+ 阻止截屏
+ 导出/导入数据
+ 导出数据
+ 数据已导出至\"Documents/MyBrain Export\"
+ 导出失败
+ 导入数据
+ 已成功导入 %1$s
+ 导入失败,请确认文件名及内容无误
+ 获取导出权限
+ 导入中....
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index a7e78480..4e0c5fea 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -7,15 +7,15 @@
Dashboard
Settings
Spaces
- App Theme
- Light Theme
- Dark Theme
+ App theme
+ Light theme
+ Dark theme
Auto
Startup screen
About
App version
Project on GitHub
- Privacy Policy
+ Privacy policy
Product
Notes
Tasks
@@ -26,7 +26,7 @@
Add task to My Brain
Search
Title
- Delete Sub task
+ Delete sub task
Add sub task
Description
Request a feature / Report a bug
@@ -44,19 +44,17 @@
Descending
Show completed tasks
Search tasks
- Save Task
- Delete Task
- Delete Task?
- Delete Note?
- Delete Bookmark?
- Delete Entry?
- Are you sure you want to delete the Task: \n \"%1$s\""
- Are you sure you want to delete the Note: \n \"%1$s\""
- Are you sure you want to delete this bookmark""
- Are you sure you want to delete this entry""
+ Save task
+ Delete task
+ Delete task?
+ Delete note?
+ Delete bookmark?
+ Delete entry?
+ Are you sure you want to delete the task: \n \"%1$s\""?
+ Are you sure you want to delete the note: \n \"%1$s\""?
+ Are you sure you want to delete this bookmark""?
+ Are you sure you want to delete this entry""?
Cancel
- Support with :
- Thank you for your support ❤
You don\'t have any tasks\n Click the + button to add a new Task\n or \nby using the shortcut in the quick settings menu
You don\'t have any notes\n Click the + button to add a new Note
You don\'t have any entries\n Click the + button to add a new entry
@@ -65,7 +63,7 @@
List
Grid
Note content (supports markdown)
- Delete Note
+ Delete note
Note cannot be empty
Pin note
Reading mode
@@ -78,8 +76,8 @@
Invalid URL
Add bookmark
Open link
- Search Bookmarks
- Delete Bookmark
+ Search bookmarks
+ Delete bookmark
URL
Cancel changes
Add entry
@@ -107,7 +105,7 @@
You mood during the month
You mood during the year
%1$d%%
- Mood Flow
+ Mood flow
Mood summary
"Your mood was "
" most of the time "
@@ -117,7 +115,7 @@
No events yet
Tasks summary
You completed
- of Tasks in the last Week
+ of tasks in the last week
No tasks yet
Loading…
Click the refresh button if you already granted the permission
@@ -128,7 +126,7 @@
Visit dentist
Buy groceries
Call mom
- App Font
+ App font
System default
Delete event
Location
@@ -138,7 +136,7 @@
Every month
Every year
Event should not be in the past
- Delete Event?
+ Delete event?
Are you sure you want do delete this event?
Folders
Create folder
@@ -150,4 +148,14 @@
Are you sure you want to delete this folder and all of its content?
Save
Edit folder
+ Block screenshots
+ Export/Import
+ Export data
+ Successfully exported data to \n\"/Documents/MyBrain Export\"
+ Something went wrong while exporting
+ Import data
+ Successfully imported %1$s
+ Something went wrong while importing. make sure that the file name and content are not corrupted
+ Grant permission to export
+ Importing....
\ No newline at end of file
diff --git a/app/src/main/res/xml/locales_config.xml b/app/src/main/res/xml/locales_config.xml
index d1dea094..5173332d 100644
--- a/app/src/main/res/xml/locales_config.xml
+++ b/app/src/main/res/xml/locales_config.xml
@@ -6,4 +6,7 @@
+
+
+
\ No newline at end of file
diff --git a/build.gradle b/build.gradle
index 23916553..08a7c546 100644
--- a/build.gradle
+++ b/build.gradle
@@ -4,8 +4,8 @@ buildscript {
}
}// Top-level build file where you can add configuration options common to all sub-projects/modules.
plugins {
- id 'com.android.application' version '7.2.2' apply false
- id 'com.android.library' version '7.2.2' apply false
+ id 'com.android.application' version '7.3.1' apply false
+ id 'com.android.library' version '7.3.1' apply false
id 'org.jetbrains.kotlin.android' version '1.7.10' apply false
id 'com.google.dagger.hilt.android' version '2.43.2' apply false
}
diff --git a/fastlane/metadata/android/en-US/changelogs/4.txt b/fastlane/metadata/android/en-US/changelogs/4.txt
new file mode 100644
index 00000000..786817f1
--- /dev/null
+++ b/fastlane/metadata/android/en-US/changelogs/4.txt
@@ -0,0 +1,8 @@
+- Added export/import data
+- Added block screenshots option
+- Changed the grid view in notes to staggered grid view
+- Added Romanian translation by @SebiTalent04
+- Added Brazilian Portuguese translation by @abChimp
+- Added German translation by @SteveMutter
+- Fixed recurring events shows only one instance
+- Bug fixes
\ No newline at end of file
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
index 055b69d7..b380d695 100644
--- a/gradle/wrapper/gradle-wrapper.properties
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -1,6 +1,6 @@
#Tue May 10 14:12:31 EET 2022
distributionBase=GRADLE_USER_HOME
-distributionUrl=https\://services.gradle.org/distributions/gradle-7.3.3-bin.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-7.4-bin.zip
distributionPath=wrapper/dists
zipStorePath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME