diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 8b2a9405df..ef99ebee80 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -167,6 +167,17 @@
+
+
+
+
+
+
diff --git a/app/src/main/java/com/anytypeio/anytype/app/DefaultAppActionManager.kt b/app/src/main/java/com/anytypeio/anytype/app/DefaultAppActionManager.kt
index d1e2d46d14..a9444a3c10 100644
--- a/app/src/main/java/com/anytypeio/anytype/app/DefaultAppActionManager.kt
+++ b/app/src/main/java/com/anytypeio/anytype/app/DefaultAppActionManager.kt
@@ -1,13 +1,16 @@
package com.anytypeio.anytype.app
import android.content.Context
+import android.content.ComponentName
import android.content.Intent
+import android.service.quicksettings.TileService
import androidx.core.content.pm.ShortcutInfoCompat
import androidx.core.content.pm.ShortcutManagerCompat
import androidx.core.graphics.drawable.IconCompat
import com.anytypeio.anytype.R
import com.anytypeio.anytype.domain.misc.AppActionManager
import com.anytypeio.anytype.ui.main.MainActivity
+import com.anytypeio.anytype.app.QuickCreateTileService
import timber.log.Timber
/**
@@ -44,6 +47,7 @@ class DefaultAppActionManager(val context: Context) : AppActionManager {
val shortcuts = ShortcutManagerCompat.getDynamicShortcuts(context).map { it.id }
ShortcutManagerCompat.removeLongLivedShortcuts(context, shortcuts)
ShortcutManagerCompat.removeAllDynamicShortcuts(context)
+ setupQuickCreateTile(null, null)
}
private fun setupCreateNewObjectAction(
@@ -66,10 +70,26 @@ class DefaultAppActionManager(val context: Context) : AppActionManager {
)
.build()
ShortcutManagerCompat.pushDynamicShortcut(context, shortcut)
+
+ if (action.isDefault) {
+ setupQuickCreateTile(action.type.key, label)
+ }
+ }
+
+ private fun setupQuickCreateTile(typeKey: String?, label: String?) {
+ val prefs = context.getSharedPreferences(QUICK_CREATE_TILE_PREFS, Context.MODE_PRIVATE)
+ val editor = prefs.edit()
+ editor.putString("typeKey", typeKey)
+ editor.putString("label", label)
+ editor.apply()
+
+ val componentName = ComponentName(context.applicationContext, QuickCreateTileService::class.java)
+ TileService.requestListeningState(context, componentName)
}
companion object {
const val ACTION_CREATE_NEW_ID = "anytype.app-action.create-new.id"
const val ACTION_CREATE_NEW_TYPE_KEY = "anytype.app-action.create-new.key"
+ const val QUICK_CREATE_TILE_PREFS = "anytype.quick-create-tile"
}
}
\ No newline at end of file
diff --git a/app/src/main/java/com/anytypeio/anytype/app/QuickCreateTileService.kt b/app/src/main/java/com/anytypeio/anytype/app/QuickCreateTileService.kt
new file mode 100644
index 0000000000..966b77c9c4
--- /dev/null
+++ b/app/src/main/java/com/anytypeio/anytype/app/QuickCreateTileService.kt
@@ -0,0 +1,63 @@
+package com.anytypeio.anytype.app
+
+import android.annotation.SuppressLint
+import android.app.PendingIntent
+import android.content.Context
+import android.content.Intent
+import android.os.Build
+import android.service.quicksettings.Tile
+import android.service.quicksettings.TileService
+import com.anytypeio.anytype.ui.main.MainActivity
+
+/**
+ * Quick Settings tile service that allows creating new objects from the quick settings panel.
+ *
+ * The tile's behavior is configured through shared preferences:
+ * - typeKey: The type of object to create when clicked
+ * - label: The display label for the tile
+ *
+ * The tile will be unavailable if no type is configured, and greyed out (but clickable) when it's set.
+ * When clicked, it launches MainActivity with an intent to create a new object of the configured type.
+ */
+class QuickCreateTileService : TileService() {
+ private var typeKey: String? = null
+
+ @SuppressLint("StartActivityAndCollapseDeprecated")
+ override fun onClick() {
+ super.onClick()
+ unlockAndRun {
+ val intent = Intent(Intent.ACTION_VIEW, null).apply {
+ setClass(applicationContext, MainActivity::class.java)
+ putExtra(DefaultAppActionManager.ACTION_CREATE_NEW_TYPE_KEY, typeKey)
+ flags = Intent.FLAG_ACTIVITY_NEW_TASK
+ }
+
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) {
+ val pendingIntent = PendingIntent.getActivity(
+ applicationContext,
+ 0, // request code
+ intent,
+ PendingIntent.FLAG_IMMUTABLE
+ )
+ startActivityAndCollapse(pendingIntent)
+ } else {
+ startActivityAndCollapse(intent)
+ }
+ }
+ }
+
+ override fun onStartListening() {
+ super.onStartListening()
+ updateTile()
+ }
+
+ private fun updateTile() {
+ val prefs = getSharedPreferences(DefaultAppActionManager.QUICK_CREATE_TILE_PREFS, Context.MODE_PRIVATE)
+ typeKey = prefs.getString("typeKey", null)
+
+ val tile = qsTile
+ tile.state = if (typeKey != null) Tile.STATE_INACTIVE else Tile.STATE_UNAVAILABLE
+ tile.label = prefs.getString("label", "New Object")
+ tile.updateTile()
+ }
+}
diff --git a/app/src/main/res/drawable/ic_quick_create_tile.xml b/app/src/main/res/drawable/ic_quick_create_tile.xml
new file mode 100644
index 0000000000..a06765b9e1
--- /dev/null
+++ b/app/src/main/res/drawable/ic_quick_create_tile.xml
@@ -0,0 +1,20 @@
+
+
+
+
+
+
+
diff --git a/domain/src/main/java/com/anytypeio/anytype/domain/misc/AppActionManager.kt b/domain/src/main/java/com/anytypeio/anytype/domain/misc/AppActionManager.kt
index b4a9030019..0a7f359044 100644
--- a/domain/src/main/java/com/anytypeio/anytype/domain/misc/AppActionManager.kt
+++ b/domain/src/main/java/com/anytypeio/anytype/domain/misc/AppActionManager.kt
@@ -9,7 +9,7 @@ interface AppActionManager {
fun setup(actions: List)
sealed class Action {
- data class CreateNew(val type: TypeKey, val name: String) : Action()
+ data class CreateNew(val type: TypeKey, val name: String, val isDefault: Boolean = false) : Action()
object ClearAll: Action()
}
}
\ No newline at end of file
diff --git a/presentation/src/main/java/com/anytypeio/anytype/presentation/home/HomeScreenViewModel.kt b/presentation/src/main/java/com/anytypeio/anytype/presentation/home/HomeScreenViewModel.kt
index 8a416bb987..40683e7d48 100644
--- a/presentation/src/main/java/com/anytypeio/anytype/presentation/home/HomeScreenViewModel.kt
+++ b/presentation/src/main/java/com/anytypeio/anytype/presentation/home/HomeScreenViewModel.kt
@@ -1715,7 +1715,8 @@ class HomeScreenViewModel(
if (type.map.containsKey(Relations.UNIQUE_KEY)) {
AppActionManager.Action.CreateNew(
type = TypeKey(type.uniqueKey),
- name = type.name.orEmpty()
+ name = type.name.orEmpty(),
+ isDefault = defaultObjectType?.key == type.uniqueKey
)
} else {
null
diff --git a/presentation/src/main/java/com/anytypeio/anytype/presentation/settings/PersonalizationSettingsViewModel.kt b/presentation/src/main/java/com/anytypeio/anytype/presentation/settings/PersonalizationSettingsViewModel.kt
index 68a594bbbb..7c44cabd3e 100644
--- a/presentation/src/main/java/com/anytypeio/anytype/presentation/settings/PersonalizationSettingsViewModel.kt
+++ b/presentation/src/main/java/com/anytypeio/anytype/presentation/settings/PersonalizationSettingsViewModel.kt
@@ -139,6 +139,7 @@ class PersonalizationSettingsViewModel(
)
).process(
success = { wrappers ->
+ val defaultObjectType = getDefaultObjectType.async(SpaceId(spaceManager.get())).getOrNull()?.type
val types = wrappers
.map { ObjectWrapper.Type(it.map) }
.sortedBy { keys.indexOf(it.uniqueKey) }
@@ -146,7 +147,8 @@ class PersonalizationSettingsViewModel(
val actions = types.map { type ->
AppActionManager.Action.CreateNew(
type = TypeKey(type.uniqueKey),
- name = type.name.orEmpty()
+ name = type.name.orEmpty(),
+ isDefault = type.uniqueKey == defaultObjectType?.key
)
}
appActionManager.setup(actions = actions)