1
0
Fork 0
mirror of https://github.com/anyproto/anytype-kotlin.git synced 2025-06-08 05:47:05 +09:00

App | Feature | Wallpaper (#1995)

This commit is contained in:
Evgenii Kozlov 2021-12-08 11:24:13 +03:00 committed by GitHub
parent 9b3644228c
commit 9fb20f0edd
Signed by: github
GPG key ID: 4AEE18F83AFDEB23
58 changed files with 857 additions and 39 deletions

View file

@ -1,11 +1,12 @@
# Change log for Android @Anytype app.
## Version 0.4.5 (WIP)
## Version 0.5.0 (WIP)
### New features & enhancements 🚀
* App | Reminding our users about saving the mnemonic phrase (#1982)
* App | Offload your files from device (#1990)
* App | Wallpapers (#1995)
### Fixes & tech 🚒

View file

@ -6,6 +6,13 @@ import com.anytypeio.anytype.presentation.editor.cover.CoverGradient
class DefaultGradientCollectionProvider : GradientCollectionProvider {
override fun provide(): List<Id> = listOf(
CoverGradient.YELLOW, CoverGradient.RED, CoverGradient.BLUE, CoverGradient.TEAL
CoverGradient.YELLOW,
CoverGradient.RED,
CoverGradient.BLUE,
CoverGradient.TEAL,
CoverGradient.PINK_ORANGE,
CoverGradient.BLUE_PINK,
CoverGradient.GREEN_ORANGE,
CoverGradient.SKY
)
}

View file

@ -9,6 +9,7 @@ import com.anytypeio.anytype.di.feature.sets.PickConditionModule
import com.anytypeio.anytype.di.feature.sets.SelectFilterRelationModule
import com.anytypeio.anytype.di.feature.sets.viewer.ViewerCardSizeSelectModule
import com.anytypeio.anytype.di.feature.sets.viewer.ViewerImagePreviewSelectModule
import com.anytypeio.anytype.di.feature.wallpaper.WallpaperSelectModule
import com.anytypeio.anytype.di.main.MainComponent
class ComponentManager(private val main: MainComponent) {
@ -106,6 +107,13 @@ class ComponentManager(private val main: MainComponent) {
.build()
}
val wallpaperSelectComponent = Component {
main
.wallpaperSelectComponent()
.module(WallpaperSelectModule)
.build()
}
val editorComponent = ComponentMap {
main
.editorComponentBuilder()

View file

@ -5,7 +5,10 @@ import com.anytypeio.anytype.core_utils.di.scope.PerScreen
import com.anytypeio.anytype.domain.auth.interactor.LaunchAccount
import com.anytypeio.anytype.domain.auth.repo.AuthRepository
import com.anytypeio.anytype.domain.config.FlavourConfigProvider
import com.anytypeio.anytype.domain.config.UserSettingsRepository
import com.anytypeio.anytype.domain.device.PathProvider
import com.anytypeio.anytype.domain.wallpaper.ObserveWallpaper
import com.anytypeio.anytype.domain.wallpaper.RestoreWallpaper
import com.anytypeio.anytype.presentation.main.MainViewModelFactory
import com.anytypeio.anytype.ui.main.MainActivity
import dagger.Module
@ -34,8 +37,15 @@ object MainEntryModule {
@Provides
fun provideMainViewModelFactory(
launchAccount: LaunchAccount,
analytics: Analytics
): MainViewModelFactory = MainViewModelFactory(launchAccount, analytics)
analytics: Analytics,
observeWallpaper: ObserveWallpaper,
restoreWallpaper: RestoreWallpaper
): MainViewModelFactory = MainViewModelFactory(
launchAccount = launchAccount,
analytics = analytics,
observeWallpaper = observeWallpaper,
restoreWallpaper = restoreWallpaper
)
@JvmStatic
@PerScreen
@ -50,4 +60,16 @@ object MainEntryModule {
context = Dispatchers.Main,
flavourConfigProvider = flavourConfigProvider
)
@JvmStatic
@PerScreen
@Provides
fun provideObserveWallpaperUseCase() : ObserveWallpaper = ObserveWallpaper()
@JvmStatic
@PerScreen
@Provides
fun provideRestoreWallpaperUseCase(
repo: UserSettingsRepository
) : RestoreWallpaper = RestoreWallpaper(repo)
}

View file

@ -0,0 +1,43 @@
package com.anytypeio.anytype.di.feature.wallpaper
import com.anytypeio.anytype.core_utils.di.scope.PerScreen
import com.anytypeio.anytype.domain.config.UserSettingsRepository
import com.anytypeio.anytype.domain.wallpaper.SetWallpaper
import com.anytypeio.anytype.presentation.wallpaper.WallpaperSelectViewModel
import com.anytypeio.anytype.ui.dashboard.WallpaperSelectFragment
import dagger.Module
import dagger.Provides
import dagger.Subcomponent
@Subcomponent(
modules = [WallpaperSelectModule::class]
)
@PerScreen
interface WallpaperSelectSubComponent {
@Subcomponent.Builder
interface Builder {
fun module(module: WallpaperSelectModule): Builder
fun build(): WallpaperSelectSubComponent
}
fun inject(fragment: WallpaperSelectFragment)
}
@Module
object WallpaperSelectModule {
@JvmStatic
@Provides
@PerScreen
fun provideViewModelFactory(
setWallpaper: SetWallpaper
): WallpaperSelectViewModel.Factory = WallpaperSelectViewModel.Factory(
setWallpaper = setWallpaper
)
@JvmStatic
@Provides
@PerScreen
fun provideSetWallpaper(repo: UserSettingsRepository) : SetWallpaper = SetWallpaper(repo)
}

View file

@ -2,6 +2,7 @@ package com.anytypeio.anytype.di.main
import com.anytypeio.anytype.app.AndroidApplication
import com.anytypeio.anytype.di.feature.*
import com.anytypeio.anytype.di.feature.wallpaper.WallpaperSelectSubComponent
import dagger.Component
import javax.inject.Singleton
@ -43,4 +44,5 @@ interface MainComponent {
fun objectSetComponentBuilder(): ObjectSetSubComponent.Builder
fun otherSettingsComponentBuilder(): OtherSettingsSubComponent.Builder
fun objectTypeChangeComponent(): ObjectTypeChangeSubComponent.Builder
fun wallpaperSelectComponent(): WallpaperSelectSubComponent.Builder
}

View file

@ -0,0 +1,89 @@
package com.anytypeio.anytype.ui.dashboard
import android.graphics.Rect
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.viewModels
import androidx.lifecycle.lifecycleScope
import androidx.recyclerview.widget.GridLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.anytypeio.anytype.R
import com.anytypeio.anytype.core_ui.features.wallpaper.WallpaperSelectAdapter
import com.anytypeio.anytype.core_utils.ext.dimen
import com.anytypeio.anytype.core_utils.ext.subscribe
import com.anytypeio.anytype.core_utils.ui.BaseBottomSheetFragment
import com.anytypeio.anytype.di.common.componentManager
import com.anytypeio.anytype.presentation.wallpaper.WallpaperSelectViewModel
import kotlinx.android.synthetic.main.fragment_wallpaper_select.*
import javax.inject.Inject
class WallpaperSelectFragment : BaseBottomSheetFragment() {
@Inject
lateinit var factory: WallpaperSelectViewModel.Factory
private val vm by viewModels<WallpaperSelectViewModel> { factory }
private val wallpaperSelectAdapter by lazy {
WallpaperSelectAdapter { vm.onWallpaperSelected(it) }
}
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? = inflater.inflate(R.layout.fragment_wallpaper_select, container, false)
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
val spacing = requireContext().dimen(R.dimen.cover_gallery_item_spacing).toInt()
wallpaperRecycler.apply {
adapter = wallpaperSelectAdapter
layoutManager = GridLayoutManager(context, 3).apply {
spanSizeLookup = object : GridLayoutManager.SpanSizeLookup() {
override fun getSpanSize(position: Int): Int {
return when (wallpaperSelectAdapter.getItemViewType(position)) {
R.layout.item_wallpaper_select_section -> 3
else -> 1
}
}
}
}
addItemDecoration(
object : RecyclerView.ItemDecoration() {
override fun getItemOffsets(outRect: Rect, view: View, parent: RecyclerView, state: RecyclerView.State) {
val position = parent.getChildAdapterPosition(view)
val holder = parent.findViewHolderForLayoutPosition(position)
if (holder !is WallpaperSelectAdapter.SectionViewHolder) {
outRect.left = spacing
outRect.right = spacing
outRect.top = spacing * 2
outRect.bottom = 0
}
// Drawing space at the bottom of the two last wallpapers. TODO refact.
if (position == state.itemCount - 2) {
outRect.bottom = spacing * 2
}
if (position == state.itemCount - 1) {
outRect.bottom = spacing * 2
}
}
}
)
}
with(lifecycleScope) {
subscribe(vm.state) { wallpaperSelectAdapter.update(it) }
subscribe(vm.isDismissed) { isDismissed -> if (isDismissed) dismiss() }
}
}
override fun injectDependencies() {
componentManager().wallpaperSelectComponent.get().inject(this)
}
override fun releaseDependencies() {
componentManager().wallpaperSelectComponent.release()
}
}

View file

@ -1,16 +1,23 @@
package com.anytypeio.anytype.ui.main
import android.content.Context
import android.graphics.Color
import android.os.Bundle
import androidx.activity.viewModels
import androidx.appcompat.app.AppCompatActivity
import androidx.lifecycle.lifecycleScope
import androidx.navigation.findNavController
import com.anytypeio.anytype.R
import com.anytypeio.anytype.core_models.Wallpaper
import com.anytypeio.anytype.core_utils.ext.subscribe
import com.anytypeio.anytype.di.common.componentManager
import com.anytypeio.anytype.navigation.Navigator
import com.anytypeio.anytype.presentation.editor.cover.CoverGradient
import com.anytypeio.anytype.presentation.main.MainViewModel
import com.anytypeio.anytype.presentation.main.MainViewModelFactory
import com.anytypeio.anytype.presentation.navigation.AppNavigation
import com.anytypeio.anytype.presentation.wallpaper.WallpaperColor
import kotlinx.android.synthetic.main.activity_main.*
import javax.inject.Inject
class MainActivity : AppCompatActivity(R.layout.activity_main), AppNavigation.Provider {
@ -29,6 +36,38 @@ class MainActivity : AppCompatActivity(R.layout.activity_main), AppNavigation.Pr
super.onCreate(savedInstanceState)
inject()
if (savedInstanceState != null) vm.onRestore()
with(lifecycleScope) {
subscribe(vm.wallpaper) { wallpaper -> setWallpaper(wallpaper) }
}
}
private fun setWallpaper(wallpaper: Wallpaper) {
when (wallpaper) {
is Wallpaper.Gradient -> {
when(wallpaper.code) {
CoverGradient.YELLOW -> fragment.setBackgroundResource(R.drawable.cover_gradient_yellow)
CoverGradient.RED -> fragment.setBackgroundResource(R.drawable.cover_gradient_red)
CoverGradient.BLUE -> fragment.setBackgroundResource(R.drawable.cover_gradient_blue)
CoverGradient.TEAL -> fragment.setBackgroundResource(R.drawable.cover_gradient_teal)
CoverGradient.PINK_ORANGE -> fragment.setBackgroundResource(R.drawable.wallpaper_gradient_1)
CoverGradient.BLUE_PINK -> fragment.setBackgroundResource(R.drawable.wallpaper_gradient_2)
CoverGradient.GREEN_ORANGE -> fragment.setBackgroundResource(R.drawable.wallpaper_gradient_3)
CoverGradient.SKY -> fragment.setBackgroundResource(R.drawable.wallpaper_gradient_4)
}
}
is Wallpaper.Default -> {
fragment.setBackgroundResource(R.color.default_dashboard_background_color)
}
is Wallpaper.Color -> {
val color = WallpaperColor.values().find { it.code == wallpaper.code }
if (color != null) {
fragment.setBackgroundColor(Color.parseColor(color.hex))
}
}
is Wallpaper.Image -> {
fragment.setBackgroundResource(R.color.default_dashboard_background_color)
}
}
}
override fun onResume() {

View file

@ -4,6 +4,7 @@ import android.os.Bundle
import android.view.View
import androidx.fragment.app.viewModels
import androidx.lifecycle.lifecycleScope
import androidx.navigation.fragment.findNavController
import com.anytypeio.anytype.BuildConfig
import com.anytypeio.anytype.R
import com.anytypeio.anytype.core_ui.extensions.avatarColor
@ -50,8 +51,7 @@ class ProfileFragment : ViewStateFragment<ViewState<ProfileView>>(R.layout.fragm
when (state) {
is ViewState.Init -> {
wallpaperText.setOnClickListener {
vm.onWallpaperClicked()
toast("Coming soon...")
findNavController().navigate(R.id.wallpaperSetFragment)
}
logoutButton.setOnClickListener { vm.onLogoutClicked() }
pinCodeText.setOnClickListener {

View file

@ -418,6 +418,10 @@ open class ObjectSetFragment :
CoverGradient.RED -> setBackgroundResource(com.anytypeio.anytype.core_ui.R.drawable.cover_gradient_red)
CoverGradient.BLUE -> setBackgroundResource(com.anytypeio.anytype.core_ui.R.drawable.cover_gradient_blue)
CoverGradient.TEAL -> setBackgroundResource(com.anytypeio.anytype.core_ui.R.drawable.cover_gradient_teal)
CoverGradient.PINK_ORANGE -> setBackgroundResource(com.anytypeio.anytype.core_ui.R.drawable.wallpaper_gradient_1)
CoverGradient.BLUE_PINK -> setBackgroundResource(com.anytypeio.anytype.core_ui.R.drawable.wallpaper_gradient_2)
CoverGradient.GREEN_ORANGE -> setBackgroundResource(com.anytypeio.anytype.core_ui.R.drawable.wallpaper_gradient_3)
CoverGradient.SKY -> setBackgroundResource(com.anytypeio.anytype.core_ui.R.drawable.wallpaper_gradient_4)
}
}
container.updatePadding(top = 0)

View file

@ -6,6 +6,7 @@
android:name="androidx.navigation.fragment.NavHostFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/default_dashboard_background_color"
app:defaultNavHost="true"
app:navGraph="@navigation/graph"
tools:context=".ui.main.MainActivity" />

View file

@ -2,8 +2,7 @@
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/auth_background_color">
android:layout_height="match_parent">
<androidx.cardview.widget.CardView
android:id="@+id/container"

View file

@ -4,7 +4,6 @@
android:id="@+id/dashboardRoot"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/default_dashboard_background_color"
app:layoutDescription="@xml/fragment_dashboard_scene">
<TextView

View file

@ -3,15 +3,14 @@
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@drawable/gradient_rectangle">
android:layout_height="match_parent">
<TextView
android:id="@+id/textView2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="32dp"
android:fontFamily="@font/graphik_medium"
android:fontFamily="@font/inter_bold"
android:text="Debug settings"
android:textColor="@color/white"
android:textSize="20sp"
@ -25,7 +24,9 @@
android:layout_height="wrap_content"
android:layout_marginTop="32dp"
android:background="@color/white"
android:fontFamily="@font/inter_regular"
android:text="Debug Sync"
android:textAllCaps="false"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/textView2" />
@ -36,7 +37,9 @@
android:layout_height="wrap_content"
android:layout_marginTop="32dp"
android:background="@color/white"
android:fontFamily="@font/inter_regular"
android:text="Debug Local Store"
android:textAllCaps="false"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/btnSync" />

View file

@ -2,8 +2,7 @@
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/auth_background_color">
android:layout_height="match_parent">
<androidx.cardview.widget.CardView
android:layout_width="0dp"

View file

@ -3,8 +3,7 @@
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/auth_background_color">
android:layout_height="match_parent">
<androidx.cardview.widget.CardView
android:id="@+id/container"

View file

@ -5,8 +5,7 @@
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/root"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/default_dashboard_background_color">
android:layout_height="match_parent">
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/sheet"

View file

@ -7,6 +7,7 @@
android:layout_height="match_parent"
android:focusable="true"
android:focusableInTouchMode="true"
android:background="@color/white"
app:layoutDescription="@xml/fragment_object_set_scene">
<com.google.android.material.progressindicator.LinearProgressIndicator

View file

@ -5,7 +5,6 @@
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".ui.profile.ProfileFragment"
android:background="@color/default_dashboard_background_color"
android:scrollbars="none">
<FrameLayout

View file

@ -3,8 +3,7 @@
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:tools="http://schemas.android.com/tools"
android:background="@color/auth_background_color">
xmlns:tools="http://schemas.android.com/tools">
<TextView
android:layout_marginStart="24dp"

View file

@ -3,8 +3,7 @@
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/auth_background_color">
android:layout_height="match_parent">
<LinearLayout
android:layout_width="match_parent"

View file

@ -3,8 +3,7 @@
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/auth_background_color">
android:layout_height="match_parent">
<LinearLayout
android:layout_width="match_parent"

View file

@ -2,8 +2,7 @@
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/auth_background_color">
android:layout_height="match_parent">
<ImageView
android:id="@+id/logo"

View file

@ -0,0 +1,37 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<View
android:id="@+id/dragger"
android:layout_width="48dp"
android:layout_height="4dp"
android:layout_gravity="center_horizontal"
android:layout_marginTop="6dp"
android:background="@drawable/dragger" />
<FrameLayout
android:layout_width="match_parent"
android:layout_height="@dimen/default_toolbar_height">
<TextView
style="@style/DefaultDataViewModalHeaderStyle"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="center"
android:gravity="center"
android:text="Change wallpaper" />
</FrameLayout>
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/wallpaperRecycler"
android:layout_width="match_parent"
android:paddingStart="8dp"
android:paddingEnd="8dp"
android:layout_weight="1"
android:layout_height="0dp"/>
</LinearLayout>

View file

@ -425,8 +425,12 @@
android:id="@+id/userSettingsFragment"
android:name="com.anytypeio.anytype.ui.settings.OtherSettingsFragment"
android:label="fragment_user_settings"
tools:layout="@layout/fragment_user_settings" >
</dialog>
tools:layout="@layout/fragment_user_settings"/>
<dialog
android:id="@+id/wallpaperSetFragment"
android:name="com.anytypeio.anytype.ui.dashboard.WallpaperSelectFragment"
android:label="fragment_wallpaper_set"
tools:layout="@layout/fragment_wallpaper_select"/>
<dialog
android:id="@+id/objectTypeChangeFragment"
android:name="com.anytypeio.anytype.ui.objects.ObjectTypeChangeFragment"

View file

@ -21,8 +21,8 @@
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
<CustomAttribute
app:attributeName="textColor"
app:customColorValue="@color/white" />
app:attributeName="alpha"
app:customFloatValue="1.0" />
</Constraint>
<Constraint
android:id="@+id/avatarContainer"
@ -102,8 +102,8 @@
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
<CustomAttribute
app:attributeName="textColor"
app:customColorValue="#0066C3" />
app:attributeName="alpha"
app:customFloatValue="0.0" />
</Constraint>
<Constraint
android:id="@+id/avatarContainer"

View file

@ -0,0 +1,8 @@
package com.anytypeio.anytype.core_models
sealed class Wallpaper {
object Default: Wallpaper()
data class Color(val code: Id) : Wallpaper()
data class Gradient(val code: Id) : Wallpaper()
data class Image(val hash: Hash) : Wallpaper()
}

View file

@ -116,6 +116,10 @@ sealed class Title(view: View) : BlockViewHolder(view), TextHolder {
CoverGradient.RED -> setBackgroundResource(R.drawable.cover_gradient_red)
CoverGradient.BLUE -> setBackgroundResource(R.drawable.cover_gradient_blue)
CoverGradient.TEAL -> setBackgroundResource(R.drawable.cover_gradient_teal)
CoverGradient.PINK_ORANGE -> setBackgroundResource(R.drawable.wallpaper_gradient_1)
CoverGradient.BLUE_PINK -> setBackgroundResource(R.drawable.wallpaper_gradient_2)
CoverGradient.GREEN_ORANGE -> setBackgroundResource(R.drawable.wallpaper_gradient_3)
CoverGradient.SKY -> setBackgroundResource(R.drawable.wallpaper_gradient_4)
}
visible()
}

View file

@ -118,6 +118,10 @@ class DocCoverGalleryAdapter(
CoverGradient.RED -> setBackgroundResource(R.drawable.cover_gradient_red)
CoverGradient.BLUE -> setBackgroundResource(R.drawable.cover_gradient_blue)
CoverGradient.TEAL -> setBackgroundResource(R.drawable.cover_gradient_teal)
CoverGradient.PINK_ORANGE -> setBackgroundResource(R.drawable.wallpaper_gradient_1)
CoverGradient.BLUE_PINK -> setBackgroundResource(R.drawable.wallpaper_gradient_2)
CoverGradient.GREEN_ORANGE -> setBackgroundResource(R.drawable.wallpaper_gradient_3)
CoverGradient.SKY -> setBackgroundResource(R.drawable.wallpaper_gradient_4)
}
}
}

View file

@ -0,0 +1,146 @@
package com.anytypeio.anytype.core_ui.features.wallpaper
import android.graphics.Color
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView
import com.anytypeio.anytype.core_ui.R
import com.anytypeio.anytype.core_ui.extensions.tint
import com.anytypeio.anytype.presentation.editor.cover.CoverGradient
import com.anytypeio.anytype.presentation.wallpaper.WallpaperColor
import com.anytypeio.anytype.presentation.wallpaper.WallpaperSelectView
import com.anytypeio.anytype.presentation.wallpaper.WallpaperView
import kotlinx.android.synthetic.main.item_wallpaper_select_section.view.*
class WallpaperSelectAdapter(
val onWallpaperSelected: (WallpaperView) -> Unit
) : RecyclerView.Adapter<WallpaperSelectAdapter.VH>() {
private var items: List<WallpaperSelectView> = emptyList()
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): VH = when (viewType) {
R.layout.item_wallpaper_select_section -> SectionViewHolder(parent)
R.layout.item_wallpaper_select_gradient -> GradientViewHolder(parent).apply {
itemView.setOnClickListener {
val pos = bindingAdapterPosition
if (pos != RecyclerView.NO_POSITION) {
val item = items[pos]
if (item is WallpaperSelectView.Wallpaper)
onWallpaperSelected(item.item)
}
}
}
R.layout.item_wallpaper_select_solid_color -> SolidColorViewHolder(parent).apply {
itemView.setOnClickListener {
val pos = bindingAdapterPosition
if (pos != RecyclerView.NO_POSITION) {
val item = items[pos]
if (item is WallpaperSelectView.Wallpaper)
onWallpaperSelected(item.item)
}
}
}
else -> throw IllegalStateException("Unexpected view type: $viewType")
}
override fun onBindViewHolder(holder: VH, position: Int) {
when (holder) {
is GradientViewHolder -> {
val item = items[position]
check(item is WallpaperSelectView.Wallpaper)
holder.bind(item)
}
is SolidColorViewHolder -> {
val item = items[position]
check(item is WallpaperSelectView.Wallpaper)
holder.bind(item)
}
is SectionViewHolder -> {
val item = items[position]
check(item is WallpaperSelectView.Section)
holder.bind(item)
}
}
}
override fun getItemCount(): Int = items.size
override fun getItemViewType(position: Int): Int = when (val view = items[position]) {
is WallpaperSelectView.Section -> R.layout.item_wallpaper_select_section
is WallpaperSelectView.Wallpaper -> {
if (view.item is WallpaperView.SolidColor)
R.layout.item_wallpaper_select_solid_color
else
R.layout.item_wallpaper_select_gradient
}
}
fun update(views: List<WallpaperSelectView>) {
items = views
notifyDataSetChanged()
}
sealed class VH(view: View) : RecyclerView.ViewHolder(view)
class SectionViewHolder(parent: ViewGroup) : VH(
LayoutInflater.from(parent.context).inflate(
R.layout.item_wallpaper_select_section,
parent,
false
)
) {
fun bind(item: WallpaperSelectView.Section) = with(itemView) {
when (item) {
WallpaperSelectView.Section.Gradient -> {
tvSectionName.setText(R.string.cover_gradients)
}
WallpaperSelectView.Section.SolidColor -> {
tvSectionName.setText(R.string.cover_color_solid)
}
}
}
}
class SolidColorViewHolder(parent: ViewGroup) : VH(
LayoutInflater.from(parent.context).inflate(
R.layout.item_wallpaper_select_solid_color,
parent,
false
)
) {
fun bind(wallpaper: WallpaperSelectView.Wallpaper) = with(itemView) {
val item = wallpaper.item
check(item is WallpaperView.SolidColor)
val color = WallpaperColor.values().find { it.code == item.code }
if (color != null ) {
itemView.tint(Color.parseColor(color.hex))
} else {
itemView.tint(Color.WHITE)
}
}
}
class GradientViewHolder(parent: ViewGroup) : VH(
LayoutInflater.from(parent.context).inflate(
R.layout.item_wallpaper_select_gradient,
parent,
false
)
) {
fun bind(item: WallpaperSelectView.Wallpaper) = with(itemView) {
val wallpaper = item.item
check(wallpaper is WallpaperView.Gradient)
when (wallpaper.code) {
CoverGradient.YELLOW -> setBackgroundResource(R.drawable.cover_gradient_yellow)
CoverGradient.RED -> setBackgroundResource(R.drawable.cover_gradient_red)
CoverGradient.BLUE -> setBackgroundResource(R.drawable.cover_gradient_blue)
CoverGradient.TEAL -> setBackgroundResource(R.drawable.cover_gradient_teal)
CoverGradient.PINK_ORANGE -> setBackgroundResource(R.drawable.wallpaper_gradient_1)
CoverGradient.BLUE_PINK -> setBackgroundResource(R.drawable.wallpaper_gradient_2)
CoverGradient.GREEN_ORANGE -> setBackgroundResource(R.drawable.wallpaper_gradient_3)
CoverGradient.SKY -> setBackgroundResource(R.drawable.wallpaper_gradient_4)
}
}
}
}

View file

@ -2,7 +2,7 @@
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<gradient
android:angle="180"
android:angle="-90"
android:endColor="#3e58eb"
android:startColor="#ab50cc" />
</shape>

View file

@ -2,7 +2,7 @@
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<gradient
android:angle="180"
android:angle="-90"
android:endColor="#e51ca0"
android:startColor="#f55522" />
</shape>

View file

@ -2,7 +2,7 @@
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<gradient
android:angle="180"
android:angle="-90"
android:endColor="#0fc8ba"
android:startColor="#2aa7ee" />
</shape>

View file

@ -2,7 +2,7 @@
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<gradient
android:angle="180"
android:angle="-90"
android:endColor="#ecd91b"
android:startColor="#ffb522" />
</shape>

View file

@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<gradient
android:angle="-90"
android:centerColor="#FDD0CD"
android:endColor="#FFCC81"
android:startColor="#D8A4E1" />
</shape>

View file

@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<gradient
android:angle="-90"
android:centerColor="#ABB6ED"
android:endColor="#F3BFAC"
android:startColor="#73B7F0" />
</shape>

View file

@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<gradient
android:angle="-90"
android:centerColor="#C5D3AC"
android:endColor="#F6C47A"
android:startColor="#63B3CB" />
</shape>

View file

@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<gradient
android:angle="-90"
android:centerColor="#A4CFEC"
android:endColor="#DAEAF3"
android:startColor="#6EB6E4" />
</shape>

View file

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:background="@drawable/rectangle_debug"
android:layout_height="@dimen/default_wallpaper_select_item_height">
</FrameLayout>

View file

@ -0,0 +1,18 @@
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="48dp">
<TextView
android:id="@+id/tvSectionName"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:layout_marginTop="18dp"
android:fontFamily="@font/inter_medium"
android:textColor="@color/text_secondary"
android:textSize="13sp"
tools:text="Solid color" />
</FrameLayout>

View file

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:background="@drawable/rect_cover_gallery_color"
android:layout_height="@dimen/default_wallpaper_select_item_height">
</FrameLayout>

View file

@ -201,5 +201,6 @@
<dimen name="dp_14">14dp</dimen>
<dimen name="defaultGalleryViewTextSize">12sp</dimen>
<dimen name="defaultGalleryViewAvatarTextSize">11sp</dimen>
<dimen name="default_wallpaper_select_item_height">208dp</dimen>
</resources>

View file

@ -1,6 +1,10 @@
package com.anytypeio.anytype.data.auth.repo
import com.anytypeio.anytype.core_models.Wallpaper
interface UserSettingsCache {
suspend fun setDefaultObjectType(type: String, name: String)
suspend fun getDefaultObjectType(): Pair<String?, String?>
suspend fun setWallpaper(wallpaper: Wallpaper)
suspend fun getWallpaper() : Wallpaper
}

View file

@ -1,9 +1,16 @@
package com.anytypeio.anytype.data.auth.repo
import com.anytypeio.anytype.core_models.Wallpaper
import com.anytypeio.anytype.domain.config.UserSettingsRepository
class UserSettingsDataRepository(private val cache: UserSettingsCache) : UserSettingsRepository {
override suspend fun setWallpaper(wallpaper: Wallpaper) {
cache.setWallpaper(wallpaper)
}
override suspend fun getWallpaper(): Wallpaper = cache.getWallpaper()
override suspend fun setDefaultObjectType(type: String, name: String) {
cache.setDefaultObjectType(type, name)
}

View file

@ -1,6 +1,10 @@
package com.anytypeio.anytype.domain.config
import com.anytypeio.anytype.core_models.Wallpaper
interface UserSettingsRepository {
suspend fun setWallpaper(wallpaper: Wallpaper)
suspend fun getWallpaper(): Wallpaper
suspend fun setDefaultObjectType(type: String, name: String)
suspend fun getDefaultObjectType(): Pair<String?, String?>
}

View file

@ -0,0 +1,12 @@
package com.anytypeio.anytype.domain.wallpaper
import com.anytypeio.anytype.core_models.Wallpaper
import com.anytypeio.anytype.domain.base.BaseUseCase
import com.anytypeio.anytype.domain.base.FlowUseCase
import kotlinx.coroutines.flow.Flow
class ObserveWallpaper : FlowUseCase<Wallpaper, BaseUseCase.None>() {
override fun build(params: BaseUseCase.None?): Flow<Wallpaper> {
return WallpaperStore.Default.observe()
}
}

View file

@ -0,0 +1,13 @@
package com.anytypeio.anytype.domain.wallpaper
import com.anytypeio.anytype.domain.base.BaseUseCase
import com.anytypeio.anytype.domain.config.UserSettingsRepository
class RestoreWallpaper(
private val repo: UserSettingsRepository
) : BaseUseCase<Unit, BaseUseCase.None>() {
override suspend fun run(params: None) = safe {
val restored = repo.getWallpaper()
WallpaperStore.Default.set(restored)
}
}

View file

@ -0,0 +1,32 @@
package com.anytypeio.anytype.domain.wallpaper
import com.anytypeio.anytype.core_models.Wallpaper
import com.anytypeio.anytype.domain.base.Interactor
import com.anytypeio.anytype.domain.config.UserSettingsRepository
class SetWallpaper(
private val repo: UserSettingsRepository
) : Interactor<SetWallpaper.Params>() {
override suspend fun run(params: Params) {
when (params) {
is Params.Gradient -> {
repo.setWallpaper(
Wallpaper.Gradient(params.code)
)
WallpaperStore.Default.set(Wallpaper.Gradient(params.code))
}
is Params.SolidColor -> {
repo.setWallpaper(
Wallpaper.Color(params.code)
)
WallpaperStore.Default.set(Wallpaper.Color(params.code))
}
}
}
sealed class Params {
data class SolidColor(val code: String) : Params()
data class Gradient(val code: String) : Params()
}
}

View file

@ -0,0 +1,18 @@
package com.anytypeio.anytype.domain.wallpaper
import com.anytypeio.anytype.core_models.Wallpaper
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
interface WallpaperStore {
fun set(wallpaper: Wallpaper)
fun get() : Wallpaper
fun observe() : Flow<Wallpaper>
object Default : WallpaperStore {
private val wallpaper = MutableStateFlow<Wallpaper>(Wallpaper.Default)
override fun set(wallpaper: Wallpaper) { this.wallpaper.value = wallpaper }
override fun get(): Wallpaper = wallpaper.value
override fun observe(): Flow<Wallpaper> = wallpaper
}
}

View file

@ -23,7 +23,9 @@ android {
}
dependencies {
implementation project(':data')
implementation project(':core-models')
def applicationDependencies = rootProject.ext.mainApplication
def unitTestDependencies = rootProject.ext.unitTesting

View file

@ -1,6 +1,7 @@
package com.anytypeio.anytype.persistence.repo
import android.content.SharedPreferences
import com.anytypeio.anytype.core_models.Wallpaper
import com.anytypeio.anytype.data.auth.repo.UserSettingsCache
class DefaultUserSettingsCache(private val prefs: SharedPreferences) : UserSettingsCache {
@ -18,8 +19,74 @@ class DefaultUserSettingsCache(private val prefs: SharedPreferences) : UserSetti
return Pair(type, name)
}
override suspend fun setWallpaper(wallpaper: Wallpaper) {
when (wallpaper) {
is Wallpaper.Default -> {
prefs.edit()
.remove(WALLPAPER_VALUE_KEY)
.remove(WALLPAPER_TYPE_KEY)
.apply()
}
is Wallpaper.Color -> {
prefs
.edit()
.putInt(WALLPAPER_TYPE_KEY, WALLPAPER_TYPE_COLOR)
.putString(WALLPAPER_VALUE_KEY, wallpaper.code)
.apply()
}
is Wallpaper.Gradient -> {
prefs
.edit()
.putInt(WALLPAPER_TYPE_KEY, WALLPAPER_TYPE_GRADIENT)
.putString(WALLPAPER_VALUE_KEY, wallpaper.code)
.apply()
}
is Wallpaper.Image -> {
prefs
.edit()
.putInt(WALLPAPER_TYPE_KEY, WALLPAPER_TYPE_IMAGE)
.putString(WALLPAPER_VALUE_KEY, wallpaper.hash)
.apply()
}
}
}
override suspend fun getWallpaper(): Wallpaper {
val type = prefs.getInt(WALLPAPER_TYPE_KEY, -1)
if (type != -1) {
val value = prefs.getString(WALLPAPER_VALUE_KEY, null)
if (value != null && value.isNotEmpty()) {
return when (type) {
WALLPAPER_TYPE_COLOR -> {
Wallpaper.Color(value)
}
WALLPAPER_TYPE_GRADIENT -> {
Wallpaper.Gradient(value)
}
WALLPAPER_TYPE_IMAGE -> {
Wallpaper.Image(value)
}
else -> {
Wallpaper.Default
}
}
} else {
return Wallpaper.Default
}
} else {
return Wallpaper.Default
}
}
companion object {
const val DEFAULT_OBJECT_TYPE_ID_KEY = "prefs.user_settings.default_object_type.id"
const val DEFAULT_OBJECT_TYPE_NAME_KEY = "prefs.user_settings.default_object_type.name"
const val WALLPAPER_TYPE_COLOR = 1
const val WALLPAPER_TYPE_GRADIENT = 2
const val WALLPAPER_TYPE_IMAGE = 3
const val WALLPAPER_TYPE_KEY = "prefs.user_settings.wallpaper_type"
const val WALLPAPER_VALUE_KEY = "prefs.user_settings.wallpaper_value"
}
}

View file

@ -5,4 +5,11 @@ object CoverGradient {
const val RED = "red"
const val BLUE = "blue"
const val TEAL = "teal"
const val PINK_ORANGE = "pinkOrange"
const val BLUE_PINK = "bluePink"
const val GREEN_ORANGE = "greenOrange"
const val SKY = "sky"
val default = listOf(YELLOW, RED, BLUE, TEAL, PINK_ORANGE, BLUE_PINK, GREEN_ORANGE, SKY)
}

View file

@ -8,16 +8,34 @@ import com.anytypeio.anytype.analytics.base.sendEvent
import com.anytypeio.anytype.analytics.base.updateUserProperties
import com.anytypeio.anytype.analytics.props.Props
import com.anytypeio.anytype.analytics.props.UserProperty
import com.anytypeio.anytype.core_models.Wallpaper
import com.anytypeio.anytype.domain.auth.interactor.LaunchAccount
import com.anytypeio.anytype.domain.base.BaseUseCase
import com.anytypeio.anytype.domain.wallpaper.ObserveWallpaper
import com.anytypeio.anytype.domain.wallpaper.RestoreWallpaper
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.launch
import timber.log.Timber
class MainViewModel(
private val launchAccount: LaunchAccount,
private val observeWallpaper: ObserveWallpaper,
private val restoreWallpaper: RestoreWallpaper,
private val analytics: Analytics
) : ViewModel() {
val wallpaper = MutableStateFlow<Wallpaper>(Wallpaper.Default)
init {
viewModelScope.launch { restoreWallpaper(BaseUseCase.None) }
viewModelScope.launch {
observeWallpaper.build(BaseUseCase.None).collect {
wallpaper.value = it
}
}
}
fun onRestore() {
val startTime = System.currentTimeMillis()
viewModelScope.launch {

View file

@ -4,13 +4,22 @@ import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider
import com.anytypeio.anytype.analytics.base.Analytics
import com.anytypeio.anytype.domain.auth.interactor.LaunchAccount
import com.anytypeio.anytype.domain.wallpaper.ObserveWallpaper
import com.anytypeio.anytype.domain.wallpaper.RestoreWallpaper
class MainViewModelFactory(
private val launchAccount: LaunchAccount,
private val analytics: Analytics
private val analytics: Analytics,
private val observeWallpaper: ObserveWallpaper,
private val restoreWallpaper: RestoreWallpaper
) : ViewModelProvider.Factory {
@Suppress("UNCHECKED_CAST")
override fun <T : ViewModel?> create(
modelClass: Class<T>
): T = MainViewModel(launchAccount, analytics) as T
): T = MainViewModel(
launchAccount = launchAccount,
analytics = analytics,
observeWallpaper = observeWallpaper,
restoreWallpaper = restoreWallpaper
) as T
}

View file

@ -0,0 +1,52 @@
package com.anytypeio.anytype.presentation.wallpaper
enum class WallpaperColor(val code: String, val hex: String) {
YELLOW(
hex = "#FBE885",
code = "yellow"
),
ORANGE(
hex = "#F5B748",
code = "orange"
),
RED(
hex = "#E46036",
code = "red"
),
PINK(
hex = "#E6B1A4",
code = "pink"
),
PURPLE(
hex = "#611A36",
code = "purple"
),
BLUE(
hex = "#376BE1",
code = "blue"
),
ICE(
hex = "#97CCEF",
code = "ice"
),
TEAL(
hex = "#9FB0B6",
code = "teal"
),
GREEN(
hex = "#336C45",
code = "green"
),
LIGHT_GREY(
hex = "#DFDDD1",
code = "lightgrey"
),
DARK_GREY(
hex = "#ACA998",
code = "darkgrey"
),
BLACK(
hex = "#2C2B28",
code = "black"
),
}

View file

@ -0,0 +1,9 @@
package com.anytypeio.anytype.presentation.wallpaper
sealed class WallpaperSelectView {
sealed class Section : WallpaperSelectView() {
object SolidColor: Section()
object Gradient: Section()
}
data class Wallpaper(val item: WallpaperView) : WallpaperSelectView()
}

View file

@ -0,0 +1,76 @@
package com.anytypeio.anytype.presentation.wallpaper
import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.viewModelScope
import com.anytypeio.anytype.domain.base.Interactor
import com.anytypeio.anytype.domain.wallpaper.SetWallpaper
import com.anytypeio.anytype.presentation.common.BaseViewModel
import com.anytypeio.anytype.presentation.editor.cover.CoverGradient
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.launch
class WallpaperSelectViewModel(
private val setWallpaper: SetWallpaper
) : BaseViewModel() {
val isDismissed = MutableStateFlow(false)
val state = MutableStateFlow<List<WallpaperSelectView>>(emptyList())
init {
state.value = mutableListOf<WallpaperSelectView>().apply {
add(WallpaperSelectView.Section.SolidColor)
addAll(
WallpaperColor.values().map {
WallpaperSelectView.Wallpaper(
item = WallpaperView.SolidColor(it.code)
)
}
)
add(WallpaperSelectView.Section.Gradient)
addAll(
CoverGradient.default.map { code ->
WallpaperSelectView.Wallpaper(
item = WallpaperView.Gradient(code)
)
}
)
}
}
fun onWallpaperSelected(wallpaper: WallpaperView) {
viewModelScope.launch {
val params = when(wallpaper) {
is WallpaperView.Gradient -> SetWallpaper.Params.Gradient(wallpaper.code)
is WallpaperView.SolidColor -> SetWallpaper.Params.SolidColor(wallpaper.code)
}
setWallpaper(params).collect { status ->
when(status) {
is Interactor.Status.Error -> {
}
is Interactor.Status.Started -> {
}
is Interactor.Status.Success -> {
isDismissed.value = true
}
}
}
}
}
class Factory(
private val setWallpaper: SetWallpaper
) : ViewModelProvider.Factory {
@Suppress("UNCHECKED_CAST")
override fun <T : ViewModel?> create(modelClass: Class<T>): T {
return WallpaperSelectViewModel(
setWallpaper = setWallpaper
) as T
}
}
}

View file

@ -0,0 +1,6 @@
package com.anytypeio.anytype.presentation.wallpaper
sealed class WallpaperView {
data class SolidColor(val code: String) : WallpaperView()
data class Gradient(val code: String) : WallpaperView()
}