mirror of
				https://github.com/AdrianKuta/Unbound-Drag-Drop.git
				synced 2025-10-31 08:23:40 +01:00 
			
		
		
		
	Cleanup
This commit is contained in:
		
							
								
								
									
										21
									
								
								.idea/deploymentTargetSelector.xml
									
									
									
										generated
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								.idea/deploymentTargetSelector.xml
									
									
									
										generated
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,21 @@ | |||||||
|  | <?xml version="1.0" encoding="UTF-8"?> | ||||||
|  | <project version="4"> | ||||||
|  |   <component name="deploymentTargetSelector"> | ||||||
|  |     <selectionStates> | ||||||
|  |       <SelectionState runConfigName="unbounddragdrop"> | ||||||
|  |         <option name="selectionMode" value="DROPDOWN" /> | ||||||
|  |       </SelectionState> | ||||||
|  |       <SelectionState runConfigName="app"> | ||||||
|  |         <option name="selectionMode" value="DROPDOWN" /> | ||||||
|  |         <DropdownSelection timestamp="2024-06-25T21:25:19.314095Z"> | ||||||
|  |           <Target type="DEFAULT_BOOT"> | ||||||
|  |             <handle> | ||||||
|  |               <DeviceId pluginId="LocalEmulator" identifier="path=/Users/adriankuta/.android/avd/Pixel_8_API_34.avd" /> | ||||||
|  |             </handle> | ||||||
|  |           </Target> | ||||||
|  |         </DropdownSelection> | ||||||
|  |         <DialogSelection /> | ||||||
|  |       </SelectionState> | ||||||
|  |     </selectionStates> | ||||||
|  |   </component> | ||||||
|  | </project> | ||||||
| @@ -0,0 +1,147 @@ | |||||||
|  | package com.github.adriankuta.unbounddragdrop | ||||||
|  |  | ||||||
|  | import android.os.Bundle | ||||||
|  | import androidx.activity.enableEdgeToEdge | ||||||
|  | import androidx.activity.viewModels | ||||||
|  | import androidx.appcompat.app.AppCompatActivity | ||||||
|  | import androidx.core.view.ViewCompat | ||||||
|  | import androidx.core.view.WindowInsetsCompat | ||||||
|  | import androidx.lifecycle.lifecycleScope | ||||||
|  | import androidx.recyclerview.widget.GridLayoutManager | ||||||
|  | import androidx.recyclerview.widget.RecyclerView | ||||||
|  | import com.github.adriankuta.unbounddragdrop.databinding.ActivityMainBinding | ||||||
|  | import com.github.adriankuta.unbounddragdrop.model.TaskStatus | ||||||
|  | import dev.adriankuta.unbounddragdrop.DragDropHelper | ||||||
|  | import kotlinx.coroutines.launch | ||||||
|  |  | ||||||
|  | class MainActivity : AppCompatActivity() { | ||||||
|  |  | ||||||
|  |     private val viewModel: MainViewModel by viewModels() | ||||||
|  |     private lateinit var binding: ActivityMainBinding | ||||||
|  |     private lateinit var todoAdapter: SimpleGridPageAdapter | ||||||
|  |     private lateinit var inProgressAdapter: SimpleGridPageAdapter | ||||||
|  |     private val callback = object : DragDropHelper.Callback() { | ||||||
|  |         override fun onMove( | ||||||
|  |             recyclerView: RecyclerView, | ||||||
|  |             viewHolder: RecyclerView.ViewHolder, | ||||||
|  |             targetRecyclerView: RecyclerView, | ||||||
|  |             targetViewHolder: RecyclerView.ViewHolder? | ||||||
|  |         ): Boolean { | ||||||
|  |             return onMove( | ||||||
|  |                 recyclerView, | ||||||
|  |                 viewHolder.adapterPosition, | ||||||
|  |                 targetRecyclerView, | ||||||
|  |                 targetViewHolder?.adapterPosition | ||||||
|  |             ) | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         override fun onMoved( | ||||||
|  |             recyclerView: RecyclerView, | ||||||
|  |             viewHolder: RecyclerView.ViewHolder, | ||||||
|  |             targetRecyclerView: RecyclerView, | ||||||
|  |             targetViewHolder: RecyclerView.ViewHolder? | ||||||
|  |         ) = Unit | ||||||
|  |  | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |  | ||||||
|  |     override fun onCreate(savedInstanceState: Bundle?) { | ||||||
|  |         super.onCreate(savedInstanceState) | ||||||
|  |         binding = ActivityMainBinding.inflate(layoutInflater) | ||||||
|  |         enableEdgeToEdge() | ||||||
|  |         setContentView(binding.root) | ||||||
|  |         ViewCompat.setOnApplyWindowInsetsListener(binding.main) { v, insets -> | ||||||
|  |             val systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars()) | ||||||
|  |             v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom) | ||||||
|  |             insets | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         setupRecyclerViews() | ||||||
|  |         setObservers() | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     private fun setupRecyclerViews() { | ||||||
|  |         todoAdapter = SimpleGridPageAdapter() | ||||||
|  |         inProgressAdapter = SimpleGridPageAdapter() | ||||||
|  |  | ||||||
|  |         with(binding) { | ||||||
|  |             setupRecyclerView(toDoRecyclerView, todoAdapter) | ||||||
|  |             setupRecyclerView(inProgressRecyclerView, inProgressAdapter) | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     private fun setObservers() { | ||||||
|  |         lifecycleScope.launch { | ||||||
|  |             viewModel.uiState.collect(::render) | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     private fun render(uiState: MainUiState) { | ||||||
|  |         todoAdapter.submitList(uiState.todo) | ||||||
|  |         inProgressAdapter.submitList(uiState.inProgress) | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     private fun setupRecyclerView( | ||||||
|  |         recyclerView: RecyclerView, | ||||||
|  |         adapter: RecyclerView.Adapter<*> | ||||||
|  |     ) { | ||||||
|  |         recyclerView.adapter = adapter | ||||||
|  |         recyclerView.layoutManager = | ||||||
|  |             GridLayoutManager(this, GRID_ROWS, GridLayoutManager.HORIZONTAL, false) | ||||||
|  |         DragDropHelper(callback).attachToRecyclerView(recyclerView) | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     private fun onMove( | ||||||
|  |         recyclerView: RecyclerView, | ||||||
|  |         sourcePosition: Int, | ||||||
|  |         targetRecyclerView: RecyclerView, | ||||||
|  |         targetPosition: Int? | ||||||
|  |     ): Boolean { | ||||||
|  |         if (recyclerView == targetRecyclerView) { | ||||||
|  |             onChangeOrder(recyclerView, sourcePosition, targetPosition) | ||||||
|  |         } else { | ||||||
|  |             onChangeStatus(recyclerView, sourcePosition, targetRecyclerView, targetPosition) | ||||||
|  |         } | ||||||
|  |         return true | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     private fun onChangeOrder( | ||||||
|  |         recyclerView: RecyclerView, | ||||||
|  |         sourcePosition: Int, | ||||||
|  |         targetPosition: Int? | ||||||
|  |     ) { | ||||||
|  |         targetPosition ?: return | ||||||
|  |         val taskStatus = when (recyclerView.id) { | ||||||
|  |             R.id.to_do_recycler_view -> TaskStatus.TODO | ||||||
|  |             R.id.in_progress_recycler_view -> TaskStatus.IN_PROGRESS | ||||||
|  |             else -> null | ||||||
|  |         } ?: return | ||||||
|  |  | ||||||
|  |         viewModel.onChangeOrder(taskStatus, sourcePosition, targetPosition) | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     private fun onChangeStatus( | ||||||
|  |         recyclerView: RecyclerView, | ||||||
|  |         sourcePosition: Int, | ||||||
|  |         targetRecyclerView: RecyclerView, | ||||||
|  |         targetPosition: Int? | ||||||
|  |     ) { | ||||||
|  |         val fromStatus = when (recyclerView.id) { | ||||||
|  |             R.id.to_do_recycler_view -> TaskStatus.TODO | ||||||
|  |             R.id.in_progress_recycler_view -> TaskStatus.IN_PROGRESS | ||||||
|  |             else -> null | ||||||
|  |         } | ||||||
|  |         val toStatus = when (targetRecyclerView.id) { | ||||||
|  |             R.id.to_do_recycler_view -> TaskStatus.TODO | ||||||
|  |             R.id.in_progress_recycler_view -> TaskStatus.IN_PROGRESS | ||||||
|  |             else -> null | ||||||
|  |         } | ||||||
|  |         if (fromStatus != null && toStatus != null) { | ||||||
|  |             viewModel.onChangeStatus(fromStatus, toStatus, sourcePosition, targetPosition) | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     companion object { | ||||||
|  |         const val GRID_ROWS = 2 | ||||||
|  |     } | ||||||
|  | } | ||||||
| @@ -0,0 +1,94 @@ | |||||||
|  | package com.github.adriankuta.unbounddragdrop | ||||||
|  |  | ||||||
|  | import androidx.lifecycle.ViewModel | ||||||
|  | import androidx.lifecycle.viewModelScope | ||||||
|  | import com.github.adriankuta.unbounddragdrop.model.Task | ||||||
|  | import com.github.adriankuta.unbounddragdrop.model.TaskStatus | ||||||
|  | import com.github.adriankuta.unbounddragdrop.model.TaskStatus.IN_PROGRESS | ||||||
|  | import com.github.adriankuta.unbounddragdrop.model.TaskStatus.TODO | ||||||
|  | import com.github.adriankuta.unbounddragdrop.util.WhileUiSubscribed | ||||||
|  | import kotlinx.coroutines.flow.MutableStateFlow | ||||||
|  | import kotlinx.coroutines.flow.StateFlow | ||||||
|  | import kotlinx.coroutines.flow.combine | ||||||
|  | import kotlinx.coroutines.flow.stateIn | ||||||
|  | import java.util.Collections | ||||||
|  | import java.util.UUID | ||||||
|  |  | ||||||
|  | data class MainUiState( | ||||||
|  |     val todo: List<Task> = emptyList(), | ||||||
|  |     val inProgress: List<Task> = emptyList(), | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | class MainViewModel : ViewModel() { | ||||||
|  |  | ||||||
|  |  | ||||||
|  |     private val _todoTasks = MutableStateFlow<List<Task>>(emptyList()) | ||||||
|  |     private val _inProgressTasks = MutableStateFlow<List<Task>>(emptyList()) | ||||||
|  |  | ||||||
|  |     init { | ||||||
|  |         _todoTasks.value = | ||||||
|  |             List(30) { Task(UUID.randomUUID().toString(), "Task $it", TODO) } | ||||||
|  |         _inProgressTasks.value = | ||||||
|  |             List(4) { Task(UUID.randomUUID().toString(), "Task $it", IN_PROGRESS) } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |  | ||||||
|  |     val uiState: StateFlow<MainUiState> = combine(_todoTasks, _inProgressTasks) { listA, listB -> | ||||||
|  |         MainUiState(listA, listB) | ||||||
|  |     }.stateIn( | ||||||
|  |         scope = viewModelScope, | ||||||
|  |         started = WhileUiSubscribed, | ||||||
|  |         initialValue = MainUiState() | ||||||
|  |     ) | ||||||
|  |  | ||||||
|  |     fun onChangeOrder(status: TaskStatus, sourcePosition: Int, targetPosition: Int) { | ||||||
|  |         when (status) { | ||||||
|  |             TODO -> _todoTasks.swapElements(sourcePosition, targetPosition) | ||||||
|  |             IN_PROGRESS -> _inProgressTasks.swapElements(sourcePosition, targetPosition) | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     fun onChangeStatus( | ||||||
|  |         fromStatus: TaskStatus, | ||||||
|  |         toStatus: TaskStatus, | ||||||
|  |         fromPosition: Int, | ||||||
|  |         toPosition: Int? | ||||||
|  |     ) { | ||||||
|  |         val itemToMove = when (fromStatus) { | ||||||
|  |             TODO -> _todoTasks.removeAt(fromPosition) | ||||||
|  |             IN_PROGRESS -> _inProgressTasks.removeAt(fromPosition) | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         when (toStatus) { | ||||||
|  |             TODO -> _todoTasks.add(toPosition ?: _todoTasks.size(), itemToMove) | ||||||
|  |             IN_PROGRESS -> _inProgressTasks.add(toPosition ?: _inProgressTasks.size(), itemToMove) | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     private fun <T> MutableStateFlow<List<T>>.swapElements( | ||||||
|  |         sourcePosition: Int, | ||||||
|  |         targetPosition: Int | ||||||
|  |     ) { | ||||||
|  |         val newList = value.toMutableList() | ||||||
|  |         Collections.swap(newList, sourcePosition, targetPosition) | ||||||
|  |         value = newList | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     private fun <T> MutableStateFlow<List<T>>.removeAt(index: Int): T { | ||||||
|  |         val newList = value.toMutableList() | ||||||
|  |         val removedItem = newList.removeAt(index) | ||||||
|  |         value = newList | ||||||
|  |         return removedItem | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     private fun <T> MutableStateFlow<List<T>>.add(index: Int, item: T) { | ||||||
|  |         val newList = value.toMutableList() | ||||||
|  |         newList.add(index, item) | ||||||
|  |         value = newList | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     private fun <T> MutableStateFlow<List<T>>.size(): Int { | ||||||
|  |         return value.size | ||||||
|  |     } | ||||||
|  |  | ||||||
|  | } | ||||||
| @@ -0,0 +1,13 @@ | |||||||
|  | package com.github.adriankuta.unbounddragdrop | ||||||
|  |  | ||||||
|  | import android.app.Application | ||||||
|  | import timber.log.Timber | ||||||
|  | import timber.log.Timber.DebugTree | ||||||
|  |  | ||||||
|  | class MyApplication : Application() { | ||||||
|  |  | ||||||
|  |     override fun onCreate() { | ||||||
|  |         super.onCreate() | ||||||
|  |         Timber.plant(DebugTree()) | ||||||
|  |     } | ||||||
|  | } | ||||||
| @@ -0,0 +1,56 @@ | |||||||
|  | package com.github.adriankuta.unbounddragdrop | ||||||
|  |  | ||||||
|  | import android.view.LayoutInflater | ||||||
|  | import android.view.ViewGroup | ||||||
|  | import androidx.recyclerview.widget.AsyncListDiffer | ||||||
|  | import androidx.recyclerview.widget.DiffUtil | ||||||
|  | import androidx.recyclerview.widget.RecyclerView | ||||||
|  | import com.github.adriankuta.unbounddragdrop.databinding.TextItemBinding | ||||||
|  | import com.github.adriankuta.unbounddragdrop.model.Task | ||||||
|  |  | ||||||
|  |  | ||||||
|  | class SimpleGridPageAdapter : | ||||||
|  |     RecyclerView.Adapter<SimpleGridPageAdapter.ViewHolder>() { | ||||||
|  |  | ||||||
|  |     private val diffUtil = object : DiffUtil.ItemCallback<Task>() { | ||||||
|  |         override fun areItemsTheSame(oldItem: Task, newItem: Task): Boolean { | ||||||
|  |             return oldItem.id == newItem.id | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         override fun areContentsTheSame( | ||||||
|  |             oldItem: Task, | ||||||
|  |             newItem: Task | ||||||
|  |         ): Boolean { | ||||||
|  |             return oldItem == newItem | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     private val asyncListDiffer = AsyncListDiffer(this, diffUtil) | ||||||
|  |  | ||||||
|  |     fun submitList(list: List<Task>) { | ||||||
|  |         asyncListDiffer.submitList(list) | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     override fun onCreateViewHolder(viewGroup: ViewGroup, viewType: Int): ViewHolder { | ||||||
|  |         return ViewHolder(viewGroup.inflate()) | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     override fun onBindViewHolder(viewHolder: ViewHolder, position: Int) { | ||||||
|  |         val data = asyncListDiffer.currentList[position] | ||||||
|  |         viewHolder.bind(data) | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     override fun getItemCount() = asyncListDiffer.currentList.size | ||||||
|  |  | ||||||
|  |     class ViewHolder(private val binding: TextItemBinding) : RecyclerView.ViewHolder(binding.root) { | ||||||
|  |  | ||||||
|  |         fun bind(task: Task) { | ||||||
|  |             binding.textView.text = task.title | ||||||
|  |             binding.root.isLongClickable = true | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     private fun ViewGroup.inflate() = | ||||||
|  |         TextItemBinding.inflate(LayoutInflater.from(context), this, false) | ||||||
|  |  | ||||||
|  | } | ||||||
| @@ -0,0 +1,7 @@ | |||||||
|  | package com.github.adriankuta.unbounddragdrop.model | ||||||
|  |  | ||||||
|  | data class Task( | ||||||
|  |     val id: String, | ||||||
|  |     val title: String, | ||||||
|  |     val taskStatus: TaskStatus | ||||||
|  | ) | ||||||
| @@ -0,0 +1,6 @@ | |||||||
|  | package com.github.adriankuta.unbounddragdrop.model | ||||||
|  |  | ||||||
|  | enum class TaskStatus { | ||||||
|  |     TODO, | ||||||
|  |     IN_PROGRESS | ||||||
|  | } | ||||||
| @@ -0,0 +1,32 @@ | |||||||
|  | /* | ||||||
|  |  * Copyright 2022 The Android Open Source Project | ||||||
|  |  * | ||||||
|  |  * Licensed under the Apache License, Version 2.0 (the "License"); | ||||||
|  |  * you may not use this file except in compliance with the License. | ||||||
|  |  * You may obtain a copy of the License at | ||||||
|  |  * | ||||||
|  |  *     https://www.apache.org/licenses/LICENSE-2.0 | ||||||
|  |  * | ||||||
|  |  * Unless required by applicable law or agreed to in writing, software | ||||||
|  |  * distributed under the License is distributed on an "AS IS" BASIS, | ||||||
|  |  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||||
|  |  * See the License for the specific language governing permissions and | ||||||
|  |  * limitations under the License. | ||||||
|  |  */ | ||||||
|  |  | ||||||
|  | package com.github.adriankuta.unbounddragdrop.util | ||||||
|  |  | ||||||
|  | import kotlinx.coroutines.flow.SharingStarted | ||||||
|  |  | ||||||
|  | private const val StopTimeoutMillis: Long = 5000 | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * A [SharingStarted] meant to be used with a [StateFlow] to expose data to the UI. | ||||||
|  |  * | ||||||
|  |  * When the UI stops observing, upstream flows stay active for some time to allow the system to | ||||||
|  |  * come back from a short-lived configuration change (such as rotations). If the UI stops | ||||||
|  |  * observing for longer, the cache is kept but the upstream flows are stopped. When the UI comes | ||||||
|  |  * back, the latest value is replayed and the upstream flows are executed again. This is done to | ||||||
|  |  * save resources when the app is in the background but let users switch between apps quickly. | ||||||
|  |  */ | ||||||
|  | val WhileUiSubscribed: SharingStarted = SharingStarted.WhileSubscribed(StopTimeoutMillis) | ||||||
							
								
								
									
										57
									
								
								app/src/main/res/layout/activity_main.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										57
									
								
								app/src/main/res/layout/activity_main.xml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,57 @@ | |||||||
|  | <?xml version="1.0" encoding="utf-8"?> | ||||||
|  | <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" | ||||||
|  |     xmlns:app="http://schemas.android.com/apk/res-auto" | ||||||
|  |     xmlns:tools="http://schemas.android.com/tools" | ||||||
|  |     android:id="@+id/main" | ||||||
|  |     android:layout_width="match_parent" | ||||||
|  |     android:layout_height="match_parent" | ||||||
|  |     android:background="#33aaaaaa" | ||||||
|  |     android:padding="16dp" | ||||||
|  |     tools:context=".MainActivity"> | ||||||
|  |  | ||||||
|  |     <TextView | ||||||
|  |         android:id="@+id/header" | ||||||
|  |         android:layout_width="wrap_content" | ||||||
|  |         android:layout_height="wrap_content" | ||||||
|  |         android:text="Sprint 1" | ||||||
|  |         android:textSize="22sp" | ||||||
|  |         app:layout_constraintStart_toStartOf="parent" | ||||||
|  |         app:layout_constraintTop_toTopOf="parent" /> | ||||||
|  |  | ||||||
|  |     <TextView | ||||||
|  |         android:id="@+id/todo_label" | ||||||
|  |         android:layout_width="wrap_content" | ||||||
|  |         android:layout_height="wrap_content" | ||||||
|  |         android:text="To Do" | ||||||
|  |         android:textSize="14sp" | ||||||
|  |         app:layout_constraintStart_toStartOf="parent" | ||||||
|  |         app:layout_constraintTop_toBottomOf="@id/header" /> | ||||||
|  |  | ||||||
|  |     <androidx.recyclerview.widget.RecyclerView | ||||||
|  |         android:id="@+id/to_do_recycler_view" | ||||||
|  |         android:layout_width="0dp" | ||||||
|  |         android:layout_height="wrap_content" | ||||||
|  |         app:layout_constraintEnd_toEndOf="parent" | ||||||
|  |         app:layout_constraintStart_toStartOf="parent" | ||||||
|  |         app:layout_constraintTop_toBottomOf="@id/todo_label" /> | ||||||
|  |  | ||||||
|  |     <TextView | ||||||
|  |         android:id="@+id/in_progress_label" | ||||||
|  |         android:layout_width="wrap_content" | ||||||
|  |         android:layout_height="wrap_content" | ||||||
|  |         android:paddingVertical="12dp" | ||||||
|  |         android:text="In Progress" | ||||||
|  |         android:textSize="14sp" | ||||||
|  |         app:layout_constraintStart_toStartOf="parent" | ||||||
|  |         app:layout_constraintTop_toBottomOf="@id/to_do_recycler_view" /> | ||||||
|  |  | ||||||
|  |     <androidx.recyclerview.widget.RecyclerView | ||||||
|  |         android:id="@+id/in_progress_recycler_view" | ||||||
|  |         android:layout_width="0dp" | ||||||
|  |         android:layout_height="wrap_content" | ||||||
|  |         app:layout_constraintEnd_toEndOf="parent" | ||||||
|  |         app:layout_constraintStart_toStartOf="parent" | ||||||
|  |         app:layout_constraintTop_toBottomOf="@id/in_progress_label" /> | ||||||
|  |  | ||||||
|  |  | ||||||
|  | </androidx.constraintlayout.widget.ConstraintLayout> | ||||||
							
								
								
									
										21
									
								
								app/src/main/res/layout/text_item.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								app/src/main/res/layout/text_item.xml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,21 @@ | |||||||
|  | <?xml version="1.0" encoding="utf-8"?> | ||||||
|  | <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" | ||||||
|  |     xmlns:app="http://schemas.android.com/apk/res-auto" | ||||||
|  |     android:layout_width="wrap_content" | ||||||
|  |     android:layout_height="wrap_content"> | ||||||
|  |  | ||||||
|  |     <androidx.cardview.widget.CardView | ||||||
|  |         android:layout_width="wrap_content" | ||||||
|  |         android:layout_height="wrap_content" | ||||||
|  |         android:layout_margin="12dp" | ||||||
|  |         app:cardCornerRadius="4dp"> | ||||||
|  |  | ||||||
|  |         <TextView | ||||||
|  |             android:id="@+id/text_view" | ||||||
|  |             android:layout_width="wrap_content" | ||||||
|  |             android:layout_height="wrap_content" | ||||||
|  |             android:padding="30dp" | ||||||
|  |             android:textSize="18sp" /> | ||||||
|  |     </androidx.cardview.widget.CardView> | ||||||
|  |  | ||||||
|  | </FrameLayout> | ||||||
| @@ -0,0 +1,29 @@ | |||||||
|  | /* | ||||||
|  |  * Copyright 2022 The Android Open Source Project | ||||||
|  |  * | ||||||
|  |  *   Licensed under the Apache License, Version 2.0 (the "License"); | ||||||
|  |  *   you may not use this file except in compliance with the License. | ||||||
|  |  *   You may obtain a copy of the License at | ||||||
|  |  * | ||||||
|  |  *       https://www.apache.org/licenses/LICENSE-2.0 | ||||||
|  |  * | ||||||
|  |  *   Unless required by applicable law or agreed to in writing, software | ||||||
|  |  *   distributed under the License is distributed on an "AS IS" BASIS, | ||||||
|  |  *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||||
|  |  *   See the License for the specific language governing permissions and | ||||||
|  |  *   limitations under the License. | ||||||
|  |  */ | ||||||
|  |  | ||||||
|  | import org.gradle.api.Plugin | ||||||
|  | import org.gradle.api.Project | ||||||
|  |  | ||||||
|  | class AndroidLibraryPublishConventionPlugin : Plugin<Project> { | ||||||
|  |     override fun apply(target: Project) { | ||||||
|  |         with(target) { | ||||||
|  |             with(pluginManager) { | ||||||
|  |                 apply("com.vanniktech.maven.publish") | ||||||
|  |                 apply("com.gradleup.nmcp") | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
		Reference in New Issue
	
	Block a user