diff --git a/app/src/main/java/de/jrpie/android/launcher/preferences/ExportedConfig.kt b/app/src/main/java/de/jrpie/android/launcher/preferences/ExportedConfig.kt new file mode 100644 index 0000000..1a3c159 --- /dev/null +++ b/app/src/main/java/de/jrpie/android/launcher/preferences/ExportedConfig.kt @@ -0,0 +1,324 @@ +package de.jrpie.android.launcher.preferences + +import android.content.Context +import de.jrpie.android.launcher.actions.Action +import de.jrpie.android.launcher.actions.Gesture +import de.jrpie.android.launcher.actions.ShortcutAction +import de.jrpie.android.launcher.actions.lock.LockMethod +import de.jrpie.android.launcher.apps.AbstractAppInfo +import de.jrpie.android.launcher.apps.PinnedShortcutInfo +import de.jrpie.android.launcher.preferences.theme.Background +import de.jrpie.android.launcher.preferences.theme.ColorTheme +import de.jrpie.android.launcher.preferences.theme.Font +import de.jrpie.android.launcher.widgets.AppWidget +import de.jrpie.android.launcher.widgets.BrokenAppWidget +import de.jrpie.android.launcher.widgets.Widget +import de.jrpie.android.launcher.widgets.WidgetPanel +import de.jrpie.android.launcher.widgets.generateInternalId +import de.jrpie.android.launcher.widgets.updateWidget +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable + + +@Serializable +@SerialName("launcher:config:apps:v100") +data class ExportedAppConfig( + val favorites: Set?, + val hidden: Set?, + val pinnedShortcuts: Set?, + val customNames: HashMap?, + val hideBoundApps: Boolean, + val hidePausedApps: Boolean, + val hidePrivateSpaceApps: Boolean +) { + fun restore() { + LauncherPreferences.apps().favorites(favorites) + LauncherPreferences.apps().hidden(hidden) + LauncherPreferences.apps().pinnedShortcuts(pinnedShortcuts) + LauncherPreferences.apps().customNames(customNames) + LauncherPreferences.apps().hideBoundApps(hideBoundApps) + LauncherPreferences.apps().hidePausedApps(hidePausedApps) + LauncherPreferences.apps().hidePrivateSpaceApps(hidePrivateSpaceApps) + } + + companion object { + fun export(): ExportedAppConfig { + return ExportedAppConfig( + LauncherPreferences.apps().favorites(), + LauncherPreferences.apps().hidden(), + LauncherPreferences.apps().pinnedShortcuts(), + LauncherPreferences.apps().customNames(), + LauncherPreferences.apps().hideBoundApps(), + LauncherPreferences.apps().hidePausedApps(), + LauncherPreferences.apps().hidePausedApps(), + ) + } + } +} + +@Serializable +@SerialName("launcher:config:list:v100") +data class ExportedListConfig( + val layout: ListLayout, + val reverseLayout: Boolean +) { + fun restore() { + LauncherPreferences.list().layout(layout) + LauncherPreferences.list().reverseLayout(reverseLayout) + } + + companion object { + fun export(): ExportedListConfig { + return ExportedListConfig( + LauncherPreferences.list().layout(), + LauncherPreferences.list().reverseLayout() + ) + } + } +} + +@Serializable +@SerialName("launcher:config:theme:v100") +data class ExportedThemeConfig( + val colorTheme: ColorTheme, + val background: Background, + val font: Font, + val textShadow: Boolean, + val monochromeIcons: Boolean +) { + fun restore() { + LauncherPreferences.theme().colorTheme(colorTheme) + LauncherPreferences.theme().background(background) + LauncherPreferences.theme().font(font) + LauncherPreferences.theme().textShadow(textShadow) + LauncherPreferences.theme().monochromeIcons(monochromeIcons) + } + + companion object { + fun export(): ExportedThemeConfig { + return ExportedThemeConfig( + LauncherPreferences.theme().colorTheme(), + LauncherPreferences.theme().background(), + LauncherPreferences.theme().font(), + LauncherPreferences.theme().textShadow(), + LauncherPreferences.theme().monochromeIcons() + ) + } + } +} + +@Serializable +@SerialName("launcher:config:clock:v100") +data class ExportedClockConfig( + val font: Font, + val color: Int, + val dateVisible: Boolean, + val timeVisible: Boolean, + val flipDateTime: Boolean, + val localized: Boolean, + val showSeconds: Boolean +) { + fun restore() { + LauncherPreferences.clock().font(font) + LauncherPreferences.clock().color(color) + LauncherPreferences.clock().dateVisible(dateVisible) + LauncherPreferences.clock().timeVisible(timeVisible) + LauncherPreferences.clock().flipDateTime(flipDateTime) + LauncherPreferences.clock().localized(localized) + LauncherPreferences.clock().showSeconds(showSeconds) + } + + companion object { + fun export(): ExportedClockConfig { + return ExportedClockConfig( + LauncherPreferences.clock().font(), + LauncherPreferences.clock().color(), + LauncherPreferences.clock().dateVisible(), + LauncherPreferences.clock().timeVisible(), + LauncherPreferences.clock().flipDateTime(), + LauncherPreferences.clock().localized(), + LauncherPreferences.clock().showSeconds() + ) + } + } +} + +@Serializable +@SerialName("launcher:config:display:v100") +data class ExportedDisplayConfig( + val screenTimeoutDisabled: Boolean, + val hideStatusBar: Boolean, + val hideNavigationBar: Boolean, + val rotateScreen: Boolean +) { + fun restore() { + LauncherPreferences.display().screenTimeoutDisabled(screenTimeoutDisabled) + LauncherPreferences.display().hideStatusBar(hideStatusBar) + LauncherPreferences.display().hideNavigationBar(hideNavigationBar) + LauncherPreferences.display().rotateScreen(rotateScreen) + } + + companion object { + fun export(): ExportedDisplayConfig { + return ExportedDisplayConfig( + LauncherPreferences.display().screenTimeoutDisabled(), + LauncherPreferences.display().hideStatusBar(), + LauncherPreferences.display().hideNavigationBar(), + LauncherPreferences.display().rotateScreen() + ) + } + } +} + +@Serializable +@SerialName("launcher:config:functionality:v100") +data class ExportedFunctionalityConfig( + val searchAutoLaunch: Boolean, + val searchWeb: Boolean, + val searchAutoOpenKeyboard: Boolean, + val searchAutoCloseKeyboard: Boolean +) { + fun restore() { + LauncherPreferences.functionality().searchAutoLaunch(searchAutoLaunch) + LauncherPreferences.functionality().searchWeb(searchWeb) + LauncherPreferences.functionality().searchAutoOpenKeyboard(searchAutoOpenKeyboard) + LauncherPreferences.functionality().searchAutoCloseKeyboard(searchAutoCloseKeyboard) + } + + companion object { + fun export(): ExportedFunctionalityConfig { + return ExportedFunctionalityConfig( + LauncherPreferences.functionality().searchAutoLaunch(), + LauncherPreferences.functionality().searchWeb(), + LauncherPreferences.functionality().searchAutoOpenKeyboard(), + LauncherPreferences.functionality().searchAutoCloseKeyboard() + ) + } + } +} + +@Serializable +@SerialName("launcher:config:enabledgestures:v100") +data class ExportedEnabledGesturesConfig( + val doubleSwipe: Boolean, + val edgeSwipe: Boolean, + val edgeSwipeEdgeWidth: Int +) { + fun restore() { + LauncherPreferences.enabled_gestures().doubleSwipe(doubleSwipe) + LauncherPreferences.enabled_gestures().edgeSwipe(edgeSwipe) + LauncherPreferences.enabled_gestures().edgeSwipeEdgeWidth(edgeSwipeEdgeWidth) + } + + companion object { + fun export(): ExportedEnabledGesturesConfig { + return ExportedEnabledGesturesConfig( + LauncherPreferences.enabled_gestures().doubleSwipe(), + LauncherPreferences.enabled_gestures().edgeSwipe(), + LauncherPreferences.enabled_gestures().edgeSwipeEdgeWidth() + ) + } + } +} + +@Serializable +@SerialName("launcher:config:actions:v100") +data class ExportedActionsConfig( + val lockMethod: LockMethod +) { + fun restore() { + LauncherPreferences.actions().lockMethod(lockMethod) + } + + companion object { + fun export(): ExportedActionsConfig { + return ExportedActionsConfig( + LauncherPreferences.actions().lockMethod() + ) + } + } +} + +@Serializable +@SerialName("launcher:config:widgets:v100") +data class ExportedWidgetsConfig( + val widgets: Set?, + val customPanels: Set? +) { + fun restore() { + LauncherPreferences.widgets().customPanels(customPanels) + widgets?.forEach { + it.id = generateInternalId() + updateWidget(it) + } + } + + companion object { + fun export(): ExportedWidgetsConfig { + return ExportedWidgetsConfig( + (LauncherPreferences.widgets().widgets() ?: setOf()).map { w -> + if (w is AppWidget) { + return@map BrokenAppWidget(w) + } + w + }.toSet(), + LauncherPreferences.widgets().customPanels() + ) + } + } +} + +@Serializable +@SerialName("launcher:config:v100") +class ExportedConfig( + private val actions: Map, + private val appConfig: ExportedAppConfig, + private val listConfig: ExportedListConfig, + private val themeConfig: ExportedThemeConfig, + private val clockConfig: ExportedClockConfig, + private val displayConfig: ExportedDisplayConfig, + private val functionalityConfig: ExportedFunctionalityConfig, + private val enabledGesturesConfig: ExportedEnabledGesturesConfig, + private val actionsConfig: ExportedActionsConfig, + private val widgetsConfig: ExportedWidgetsConfig +) { + fun restore(context: Context) { + resetPreferences(context) + actions.entries.forEach { entry: Map.Entry -> + Action.setActionForGesture(entry.key, entry.value) + } + appConfig.restore() + listConfig.restore() + themeConfig.restore() + clockConfig.restore() + displayConfig.restore() + functionalityConfig.restore() + enabledGesturesConfig.restore() + actionsConfig.restore() + widgetsConfig.restore() + } + + + companion object { + fun exportConfig(): ExportedConfig { + return ExportedConfig( + Gesture.entries.map { g -> + val action = Action.forGesture(g) ?: return@map null + if (action is ShortcutAction) { + return@map null + } + Pair(g, action) + }.filterNotNull().toMap(), + ExportedAppConfig.export(), + ExportedListConfig.export(), + ExportedThemeConfig.export(), + ExportedClockConfig.export(), + ExportedDisplayConfig.export(), + ExportedFunctionalityConfig.export(), + ExportedEnabledGesturesConfig.export(), + ExportedActionsConfig.export(), + ExportedWidgetsConfig.export() + ) + } + } +} \ No newline at end of file diff --git a/app/src/main/java/de/jrpie/android/launcher/ui/HomeActivity.kt b/app/src/main/java/de/jrpie/android/launcher/ui/HomeActivity.kt index 76bf443..15441bc 100644 --- a/app/src/main/java/de/jrpie/android/launcher/ui/HomeActivity.kt +++ b/app/src/main/java/de/jrpie/android/launcher/ui/HomeActivity.kt @@ -10,9 +10,12 @@ import de.jrpie.android.launcher.actions.Gesture import de.jrpie.android.launcher.actions.LauncherAction import de.jrpie.android.launcher.databinding.ActivityHomeBinding import de.jrpie.android.launcher.openTutorial +import de.jrpie.android.launcher.preferences.ExportedConfig import de.jrpie.android.launcher.preferences.LauncherPreferences import de.jrpie.android.launcher.ui.tutorial.TutorialActivity import de.jrpie.android.launcher.ui.util.LauncherGestureActivity +import kotlinx.serialization.encodeToString +import kotlinx.serialization.json.Json /** * [HomeActivity] is the actual application Launcher, @@ -58,6 +61,8 @@ class HomeActivity : UIObject, LauncherGestureActivity() { binding.buttonFallbackSettings.setOnClickListener { LauncherAction.SETTINGS.invoke(this) } + + android.util.Log.e("export", Json.encodeToString(ExportedConfig.exportConfig())) } override fun onStart() { diff --git a/app/src/main/java/de/jrpie/android/launcher/widgets/AppWidget.kt b/app/src/main/java/de/jrpie/android/launcher/widgets/AppWidget.kt index a968962..04be645 100644 --- a/app/src/main/java/de/jrpie/android/launcher/widgets/AppWidget.kt +++ b/app/src/main/java/de/jrpie/android/launcher/widgets/AppWidget.kt @@ -17,7 +17,7 @@ import kotlinx.serialization.Serializable @Serializable @SerialName("widget:app") class AppWidget( - override val id: Int, + override var id: Int, override var position: WidgetPosition = WidgetPosition(0,0,1,1), override var panelId: Int = WidgetPanel.HOME.id, override var allowInteraction: Boolean = false, diff --git a/app/src/main/java/de/jrpie/android/launcher/widgets/BrokenAppWidget.kt b/app/src/main/java/de/jrpie/android/launcher/widgets/BrokenAppWidget.kt new file mode 100644 index 0000000..4a0a80e --- /dev/null +++ b/app/src/main/java/de/jrpie/android/launcher/widgets/BrokenAppWidget.kt @@ -0,0 +1,78 @@ +package de.jrpie.android.launcher.widgets + +import android.app.Activity +import android.appwidget.AppWidgetHostView +import android.appwidget.AppWidgetProviderInfo +import android.content.Context +import android.graphics.drawable.Drawable +import android.view.View +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable + +@Serializable +@SerialName("widget:broken") +class BrokenAppWidget( + override var id: Int, + override var position: WidgetPosition = WidgetPosition(0,0,1,1), + override var panelId: Int = WidgetPanel.HOME.id, + override var allowInteraction: Boolean = false, + + val packageName: String? = null, + val className: String? = null, + val user: Int? = null +): Widget() { + + constructor(appWidget: AppWidget, id: Int = generateInternalId()): this ( + id, + appWidget.position, + appWidget.panelId, + appWidget.allowInteraction, + appWidget.packageName, + appWidget.className, + appWidget.user + ) + + constructor( + id: Int, + position: WidgetPosition, + panelId: Int, + widgetProviderInfo: AppWidgetProviderInfo + ) : + this( + id, + position, + panelId, + panelId != WidgetPanel.HOME.id, + widgetProviderInfo.provider.packageName, + widgetProviderInfo.provider.className, + widgetProviderInfo.profile.hashCode() + ) + + + override fun toString(): String { + return "BrokenWidgetInfo(id=$id, position=$position, packageName=$packageName, className=$className, user=$user)" + } + + override fun createView(activity: Activity): AppWidgetHostView? { + return null + } + + override fun findView(views: Sequence): AppWidgetHostView? { + return views.mapNotNull { it as? AppWidgetHostView }.firstOrNull { it.appWidgetId == id } + } + + override fun getIcon(context: Context): Drawable? { + return null + } + + override fun getPreview(context: Context): Drawable? { + return null + } + + override fun isConfigurable(context: Context): Boolean { + return false + } + override fun configure(activity: Activity, requestCode: Int) { + return + } +} diff --git a/app/src/main/java/de/jrpie/android/launcher/widgets/Widget.kt b/app/src/main/java/de/jrpie/android/launcher/widgets/Widget.kt index fd96f14..a08a4e0 100644 --- a/app/src/main/java/de/jrpie/android/launcher/widgets/Widget.kt +++ b/app/src/main/java/de/jrpie/android/launcher/widgets/Widget.kt @@ -11,7 +11,7 @@ import kotlinx.serialization.json.Json @Serializable sealed class Widget { - abstract val id: Int + abstract var id: Int abstract var position: WidgetPosition abstract val panelId: Int abstract var allowInteraction: Boolean