From 231bec224fee868cfeba9eaae3813cd055822132 Mon Sep 17 00:00:00 2001 From: Sylvia van Os Date: Tue, 4 Feb 2020 16:18:41 +0100 Subject: [PATCH] Support multiple frames --- .../badgemagic/adapter/TransferAdapter.kt | 122 ++++++++++++++ .../org/fossasia/badgemagic/di/Modules.kt | 2 + .../fossasia/badgemagic/ui/DrawerActivity.kt | 7 + .../ui/fragments/SavedBadgesFragment.kt | 17 +- .../ui/fragments/TextArtFragment.kt | 53 ++---- .../ui/fragments/TransferFragment.kt | 158 ++++++++++++++++++ .../fossasia/badgemagic/util/SendingUtils.kt | 16 +- .../viewmodels/TransferQueueViewModel.kt | 27 +++ .../src/main/res/layout/fragment_transfer.xml | 91 ++++++++++ .../res/layout/recycler_transfer_item.xml | 128 ++++++++++++++ android/src/main/res/menu/drawer_items.xml | 4 + android/src/main/res/values/strings.xml | 6 + 12 files changed, 575 insertions(+), 56 deletions(-) create mode 100644 android/src/main/java/org/fossasia/badgemagic/adapter/TransferAdapter.kt create mode 100644 android/src/main/java/org/fossasia/badgemagic/ui/fragments/TransferFragment.kt create mode 100644 android/src/main/java/org/fossasia/badgemagic/viewmodels/TransferQueueViewModel.kt create mode 100644 android/src/main/res/layout/fragment_transfer.xml create mode 100644 android/src/main/res/layout/recycler_transfer_item.xml diff --git a/android/src/main/java/org/fossasia/badgemagic/adapter/TransferAdapter.kt b/android/src/main/java/org/fossasia/badgemagic/adapter/TransferAdapter.kt new file mode 100644 index 00000000..9c412c85 --- /dev/null +++ b/android/src/main/java/org/fossasia/badgemagic/adapter/TransferAdapter.kt @@ -0,0 +1,122 @@ +package org.fossasia.badgemagic.adapter + +import android.content.Context +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.LinearLayout +import android.widget.TextView +import androidx.appcompat.widget.AppCompatImageView +import androidx.core.content.ContextCompat +import androidx.recyclerview.widget.RecyclerView +import com.google.android.material.chip.Chip +import org.fossasia.badgemagic.R +import org.fossasia.badgemagic.data.BadgeConfig +import org.fossasia.badgemagic.data.Message +import org.fossasia.badgemagic.helpers.JSONHelper +import org.fossasia.badgemagic.util.SendingUtils + +class TransferAdapter(private val context: Context?, private val list: List, private val listener: OnTransferItemSelected) : RecyclerView.Adapter() { + private var selectedPosition: Int = -1 + + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): TransferItemHolder { + val v = LayoutInflater.from(context).inflate(R.layout.recycler_transfer_item, parent, false) + return TransferItemHolder(v) + } + + override fun getItemViewType(position: Int) = position + + override fun getItemId(position: Int) = position.toLong() + + override fun onBindViewHolder(holder: TransferItemHolder, position: Int) { + holder.bind(list[position]) + } + + override fun getItemCount() = list.size + + fun getSelectedItem(): Message? { + return if (selectedPosition == -1) null else list[selectedPosition] + } + + fun getItems(): List { + return list + } + + inner class TransferItemHolder(itemView: View) : RecyclerView.ViewHolder(itemView) { + + private val card: LinearLayout = itemView.findViewById(R.id.card) + private val text: TextView = itemView.findViewById(R.id.text) + private val playPause: AppCompatImageView = itemView.findViewById(R.id.play_pause) + private val delete: AppCompatImageView = itemView.findViewById(R.id.button_delete) + private val chipFlash: Chip = itemView.findViewById(R.id.chip_flash) + private val chipMarquee: Chip = itemView.findViewById(R.id.chip_marquee) + private val chipInverted: Chip = itemView.findViewById(R.id.chip_inverted) + private val chipSpeed: Chip = itemView.findViewById(R.id.chip_speed) + private val chipMode: Chip = itemView.findViewById(R.id.chip_mode) + + init { + playPause.setOnClickListener { + changeCardBackgrounds() + listener.onSelected(if (selectedPosition == -1) null else list[selectedPosition]) + } + delete.setOnClickListener { + listener.onDelete(list[adapterPosition]) + } + } + + fun bind(item: Message) { + // TODO: Get item name + // text.text = item.hexStrings.toString() + text.text = "" + + card.background = when { + selectedPosition != -1 && selectedPosition == adapterPosition -> ContextCompat.getDrawable(itemView.context, R.color.colorAccent) + else -> ContextCompat.getDrawable(itemView.context, android.R.color.transparent) + } + text.setTextColor( + when { + selectedPosition != -1 && selectedPosition == adapterPosition -> ContextCompat.getColor(itemView.context, android.R.color.white) + else -> ContextCompat.getColor(itemView.context, android.R.color.black) + } + ) + playPause.setColorFilter( + when { + selectedPosition != -1 && selectedPosition == adapterPosition -> ContextCompat.getColor(itemView.context, android.R.color.white) + else -> ContextCompat.getColor(itemView.context, android.R.color.black) + } + ) + delete.setColorFilter( + when { + selectedPosition != -1 && selectedPosition == adapterPosition -> ContextCompat.getColor(itemView.context, android.R.color.white) + else -> ContextCompat.getColor(itemView.context, android.R.color.black) + } + ) + + val badge: BadgeConfig = JSONHelper.decodeJSON(SendingUtils.configToJSON(item, false)) + chipSpeed.text = (badge.speed.ordinal.plus(1)).toString() + chipMode.text = badge.mode.toString() + + chipFlash.visibility = if (badge.isFlash) View.VISIBLE else View.GONE + chipMarquee.visibility = if (badge.isMarquee) View.VISIBLE else View.GONE + chipInverted.visibility = if (badge.isInverted) View.VISIBLE else View.GONE + } + + private fun changeCardBackgrounds() { + val lastSelected = selectedPosition + + selectedPosition = when { + selectedPosition == -1 -> adapterPosition + selectedPosition != adapterPosition -> adapterPosition + else -> -1 + } + + notifyItemChanged(adapterPosition) + if (lastSelected != -1) notifyItemChanged(lastSelected) + } + } +} + +interface OnTransferItemSelected { + fun onSelected(item: Message?) + fun onDelete(item: Message) +} diff --git a/android/src/main/java/org/fossasia/badgemagic/di/Modules.kt b/android/src/main/java/org/fossasia/badgemagic/di/Modules.kt index 90bc7baf..fb515fa2 100644 --- a/android/src/main/java/org/fossasia/badgemagic/di/Modules.kt +++ b/android/src/main/java/org/fossasia/badgemagic/di/Modules.kt @@ -15,6 +15,7 @@ import org.fossasia.badgemagic.viewmodels.FilesViewModel import org.fossasia.badgemagic.viewmodels.SavedClipartViewModel import org.fossasia.badgemagic.viewmodels.SettingsViewModel import org.fossasia.badgemagic.viewmodels.TextArtViewModel +import org.fossasia.badgemagic.viewmodels.TransferQueueViewModel import org.koin.android.ext.koin.androidContext import org.koin.androidx.viewmodel.dsl.viewModel import org.koin.dsl.module @@ -28,6 +29,7 @@ val viewModelModules = module { viewModel { DrawViewModel(get()) } viewModel { DrawerViewModel(get()) } viewModel { SavedClipartViewModel(get()) } + viewModel { TransferQueueViewModel() } } val singletonModules = module { diff --git a/android/src/main/java/org/fossasia/badgemagic/ui/DrawerActivity.kt b/android/src/main/java/org/fossasia/badgemagic/ui/DrawerActivity.kt index fa95ccc8..c5ce061b 100644 --- a/android/src/main/java/org/fossasia/badgemagic/ui/DrawerActivity.kt +++ b/android/src/main/java/org/fossasia/badgemagic/ui/DrawerActivity.kt @@ -34,6 +34,7 @@ import org.fossasia.badgemagic.ui.fragments.SavedBadgesFragment import org.fossasia.badgemagic.ui.fragments.SavedClipartFragment import org.fossasia.badgemagic.ui.fragments.SettingsFragment import org.fossasia.badgemagic.ui.fragments.TextArtFragment +import org.fossasia.badgemagic.ui.fragments.TransferFragment import org.fossasia.badgemagic.util.SendingUtils import org.fossasia.badgemagic.util.StorageUtils import org.fossasia.badgemagic.viewmodels.DrawerViewModel @@ -142,6 +143,12 @@ class DrawerActivity : BaseActivity(), NavigationView.OnNavigationItemSelectedLi switchFragment(SavedClipartFragment.newInstance()) showMenu?.setGroupVisible(R.id.saved_group, false) } + R.id.transfer -> { + viewModel.swappingOrientation = false + setRotation(ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED) + switchFragment(TransferFragment.newInstance()) + showMenu?.setGroupVisible(R.id.saved_group, false) + } R.id.settings -> { viewModel.swappingOrientation = false setRotation(ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED) diff --git a/android/src/main/java/org/fossasia/badgemagic/ui/fragments/SavedBadgesFragment.kt b/android/src/main/java/org/fossasia/badgemagic/ui/fragments/SavedBadgesFragment.kt index 55429b58..123e748a 100644 --- a/android/src/main/java/org/fossasia/badgemagic/ui/fragments/SavedBadgesFragment.kt +++ b/android/src/main/java/org/fossasia/badgemagic/ui/fragments/SavedBadgesFragment.kt @@ -15,16 +15,15 @@ import org.fossasia.badgemagic.R import org.fossasia.badgemagic.adapter.OnSavedItemSelected import org.fossasia.badgemagic.adapter.SaveAdapter import org.fossasia.badgemagic.data.ConfigInfo -import org.fossasia.badgemagic.data.DataToSend +import org.fossasia.badgemagic.data.Message import org.fossasia.badgemagic.data.Mode import org.fossasia.badgemagic.data.Speed import org.fossasia.badgemagic.ui.EditBadgeActivity import org.fossasia.badgemagic.ui.base.BaseFragment -import org.fossasia.badgemagic.util.BluetoothAdapter import org.fossasia.badgemagic.util.Converters import org.fossasia.badgemagic.util.SendingUtils import org.fossasia.badgemagic.viewmodels.FilesViewModel -import org.koin.android.ext.android.inject +import org.fossasia.badgemagic.viewmodels.TransferQueueViewModel import org.koin.androidx.viewmodel.ext.android.sharedViewModel class SavedBadgesFragment : BaseFragment() { @@ -38,8 +37,7 @@ class SavedBadgesFragment : BaseFragment() { private var recyclerAdapter: SaveAdapter? = null private val viewModel by sharedViewModel() - - private val bluetoothAdapter: BluetoothAdapter by inject() + private val transferQueueViewModel by sharedViewModel() override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { return inflater.inflate(R.layout.fragment_main_save, container, false) @@ -73,7 +71,7 @@ class SavedBadgesFragment : BaseFragment() { } } - override fun getSendData(): DataToSend { + fun getMessage(): Message { val selectedItem = recyclerAdapter?.getSelectedItem() return if (selectedItem != null) { SendingUtils.returnMessageWithJSON(selectedItem.badgeJSON) @@ -111,10 +109,9 @@ class SavedBadgesFragment : BaseFragment() { } override fun export(item: ConfigInfo) { - if (bluetoothAdapter.isTurnedOn(requireContext())) { - Toast.makeText(requireContext(), getString(R.string.sending_data), Toast.LENGTH_LONG).show() - SendingUtils.sendMessage(requireContext(), getSendData()) - } + transferQueueViewModel.add(getMessage()) + // TODO: Automatically switch to transfer screen + Toast.makeText(requireContext(), getString(R.string.prepared_for_transfer), Toast.LENGTH_LONG).show() } override fun onSelected(item: ConfigInfo?) { diff --git a/android/src/main/java/org/fossasia/badgemagic/ui/fragments/TextArtFragment.kt b/android/src/main/java/org/fossasia/badgemagic/ui/fragments/TextArtFragment.kt index 3ee177b1..630eb937 100644 --- a/android/src/main/java/org/fossasia/badgemagic/ui/fragments/TextArtFragment.kt +++ b/android/src/main/java/org/fossasia/badgemagic/ui/fragments/TextArtFragment.kt @@ -28,8 +28,6 @@ import com.google.android.material.tabs.TabLayout import java.text.SimpleDateFormat import java.util.Calendar import java.util.Locale -import java.util.Timer -import java.util.TimerTask import kotlinx.android.synthetic.main.effects_layout.* import kotlinx.android.synthetic.main.fragment_main_textart.* import kotlinx.android.synthetic.main.sections_tab.* @@ -40,7 +38,6 @@ import org.fossasia.badgemagic.adapter.OnDrawableSelected import org.fossasia.badgemagic.adapter.OnModeSelected import org.fossasia.badgemagic.core.android.ext.hideKeyboard import org.fossasia.badgemagic.core.android.ext.showKeyboard -import org.fossasia.badgemagic.data.DataToSend import org.fossasia.badgemagic.data.DrawableInfo import org.fossasia.badgemagic.data.Message import org.fossasia.badgemagic.data.Mode @@ -49,14 +46,13 @@ import org.fossasia.badgemagic.data.Speed import org.fossasia.badgemagic.text.CenteredImageSpan import org.fossasia.badgemagic.ui.base.BaseFragment import org.fossasia.badgemagic.ui.custom.knob.Croller -import org.fossasia.badgemagic.util.BluetoothAdapter import org.fossasia.badgemagic.util.Converters import org.fossasia.badgemagic.util.DRAWABLE_END import org.fossasia.badgemagic.util.DRAWABLE_START import org.fossasia.badgemagic.util.ImageUtils import org.fossasia.badgemagic.util.SendingUtils import org.fossasia.badgemagic.viewmodels.TextArtViewModel -import org.koin.android.ext.android.inject +import org.fossasia.badgemagic.viewmodels.TransferQueueViewModel import org.koin.androidx.viewmodel.ext.android.sharedViewModel import pl.droidsonroids.gif.GifImageView @@ -73,8 +69,7 @@ class TextArtFragment : BaseFragment() { private val modeAdapter = ModeAdapter() private val viewModel by sharedViewModel() - - private val bluetoothAdapter: BluetoothAdapter by inject() + private val transferQueueViewModel by sharedViewModel() override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) @@ -91,20 +86,6 @@ class TextArtFragment : BaseFragment() { return inflater.inflate(R.layout.fragment_main_textart, container, false) } - override fun getSendData(): DataToSend { - textViewMainText.hideKeyboard() - return SendingUtils.convertToDeviceDataModel( - Message( - Converters.convertEditableToLEDHex(textViewMainText.text.toString(), invertLED.isChecked, viewModel.getClipArts().value - ?: SparseArray()), - flash.isChecked, - marquee.isChecked, - Speed.values()[speedKnob.progress.minus(1)], - Mode.values()[modeAdapter.getSelectedItemPosition()] - ) - ) - } - override fun initializePreview() { setPreview() } @@ -118,25 +99,17 @@ class TextArtFragment : BaseFragment() { transfer_button.setOnClickListener { if (textViewMainText.text.trim().toString() != "") { - if (bluetoothAdapter.isTurnedOn(requireContext())) { - // Easter egg - Toast.makeText(requireContext(), getString(R.string.sending_data), Toast.LENGTH_LONG).show() - - transfer_button.visibility = View.GONE - send_progress.visibility = View.VISIBLE - - val buttonTimer = Timer() - buttonTimer.schedule(object : TimerTask() { - override fun run() { - activity?.runOnUiThread { - transfer_button.visibility = View.VISIBLE - send_progress.visibility = View.GONE - } - } - }, SCAN_TIMEOUT_MS) - - SendingUtils.sendMessage(requireContext(), getSendData()) - } + textViewMainText.hideKeyboard() + transferQueueViewModel.add(Message( + Converters.convertEditableToLEDHex(textViewMainText.text.toString(), invertLED.isChecked, viewModel.getClipArts().value + ?: SparseArray()), + flash.isChecked, + marquee.isChecked, + Speed.values()[speedKnob.progress.minus(1)], + Mode.values()[modeAdapter.getSelectedItemPosition()] + )) + // TODO: Automatically switch to transfer screen + Toast.makeText(requireContext(), getString(R.string.prepared_for_transfer), Toast.LENGTH_LONG).show() } else Toast.makeText(requireContext(), getString(R.string.empty_text_to_send), Toast.LENGTH_LONG).show() } diff --git a/android/src/main/java/org/fossasia/badgemagic/ui/fragments/TransferFragment.kt b/android/src/main/java/org/fossasia/badgemagic/ui/fragments/TransferFragment.kt new file mode 100644 index 00000000..f8524dac --- /dev/null +++ b/android/src/main/java/org/fossasia/badgemagic/ui/fragments/TransferFragment.kt @@ -0,0 +1,158 @@ +package org.fossasia.badgemagic.ui.fragments + +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.Toast +import androidx.lifecycle.Observer +import androidx.recyclerview.widget.LinearLayoutManager +import kotlinx.android.synthetic.main.fragment_transfer.empty_transfer_layout +import kotlinx.android.synthetic.main.fragment_transfer.preview_badge +import kotlinx.android.synthetic.main.fragment_transfer.transferConfigRecyclerView +import kotlinx.android.synthetic.main.fragment_transfer.transfer_button +import kotlinx.android.synthetic.main.fragment_transfer.transfer_queue +import org.fossasia.badgemagic.R +import org.fossasia.badgemagic.adapter.OnTransferItemSelected +import org.fossasia.badgemagic.adapter.TransferAdapter +import org.fossasia.badgemagic.data.DataToSend +import org.fossasia.badgemagic.data.Message +import org.fossasia.badgemagic.data.Mode +import org.fossasia.badgemagic.data.Speed +import org.fossasia.badgemagic.ui.base.BaseFragment +import org.fossasia.badgemagic.util.BluetoothAdapter +import org.fossasia.badgemagic.util.Converters +import org.fossasia.badgemagic.util.SendingUtils +import org.fossasia.badgemagic.viewmodels.TransferQueueViewModel +import org.koin.android.ext.android.inject +import org.koin.androidx.viewmodel.ext.android.sharedViewModel + +class TransferFragment : BaseFragment() { + + companion object { + @JvmStatic + fun newInstance() = + TransferFragment() + } + + private var recyclerAdapter: TransferAdapter? = null + + private val viewModel by sharedViewModel() + + private val bluetoothAdapter: BluetoothAdapter by inject() + + override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { + return inflater.inflate(R.layout.fragment_transfer, container, false) + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + + setupRecycler() + updateEmptyLayout() + + transfer_button.setOnClickListener { + if (bluetoothAdapter.isTurnedOn(requireContext())) { + Toast.makeText(requireContext(), getString(R.string.sending_data), Toast.LENGTH_LONG).show() + SendingUtils.sendMessage(requireContext(), getSendData()) + } + } + } + + private fun updateEmptyLayout() { + if (viewModel.items.value.isNullOrEmpty()) { + transfer_button.visibility = View.GONE + transfer_queue.visibility = View.GONE + empty_transfer_layout.visibility = View.VISIBLE + } else { + transfer_button.visibility = View.VISIBLE + transfer_queue.visibility = View.VISIBLE + empty_transfer_layout.visibility = View.GONE + } + } + + override fun initializePreview() { + if (recyclerAdapter != null) { + val selectedItem = recyclerAdapter?.getSelectedItem() + if (selectedItem != null) { + setPreview(SendingUtils.configToJSON(selectedItem, false)) + } else { + setPreviewNull() + } + } + } + + override fun getSendData(): DataToSend { + val messages = ArrayList() + + val items = recyclerAdapter?.getItems() + if (!items.isNullOrEmpty()) { + items.forEach { + messages.add(SendingUtils.returnMessageWithJSON(SendingUtils.configToJSON(it, false))) + } + } + + if (messages.isEmpty()) { + messages.add(SendingUtils.returnDefaultMessage()) + } + + return SendingUtils.convertToDeviceDataModel(messages) + } + + private fun setupRecycler() { + if (transferConfigRecyclerView == null) return + transferConfigRecyclerView.layoutManager = LinearLayoutManager(requireContext()) + + viewModel.items.observe(this, Observer { items -> + recyclerAdapter = null + transferConfigRecyclerView.adapter = null + + recyclerAdapter = TransferAdapter(requireContext(), items, object : OnTransferItemSelected { + override fun onDelete(item: Message) { + delete(item) + } + + override fun onSelected(item: Message?) { + if (item != null) + setPreview(SendingUtils.configToJSON(item, false)) + else + setPreviewNull() + } + }) + transferConfigRecyclerView.adapter = recyclerAdapter + updateEmptyLayout() + }) + } + + private fun delete(item: Message) { + viewModel.remove(item) + setPreviewNull() + setupRecycler() + } + + private fun setPreviewNull() { + preview_badge.setValue( + Converters.convertTextToLEDHex( + " ", + false + ).second, + ifMar = false, + ifFla = false, + speed = Speed.ONE, + mode = Mode.LEFT + ) + } + + private fun setPreview(badgeJSON: String) { + val badgeConfig = SendingUtils.getBadgeFromJSON(badgeJSON) + + preview_badge.setValue( + Converters.fixLEDHex( + badgeConfig.hexStrings, badgeConfig.isInverted), + badgeConfig.isMarquee, + badgeConfig.isFlash, + badgeConfig.speed, + badgeConfig.mode + ) + } +} diff --git a/android/src/main/java/org/fossasia/badgemagic/util/SendingUtils.kt b/android/src/main/java/org/fossasia/badgemagic/util/SendingUtils.kt index 7e9f2e65..3951c4d1 100644 --- a/android/src/main/java/org/fossasia/badgemagic/util/SendingUtils.kt +++ b/android/src/main/java/org/fossasia/badgemagic/util/SendingUtils.kt @@ -59,8 +59,12 @@ object SendingUtils { return DataToSend(listOf(message)) } - fun returnDefaultMessage(): DataToSend { - return DataToSend(listOf(Message( + fun convertToDeviceDataModel(messages: List): DataToSend { + return DataToSend(messages) + } + + fun returnDefaultMessage(): Message { + return Message( Converters.convertTextToLEDHex( " ", false @@ -69,18 +73,18 @@ object SendingUtils { marquee = false, speed = Speed.ONE, mode = Mode.LEFT - ))) + ) } - fun returnMessageWithJSON(badgeJSON: String): DataToSend { + fun returnMessageWithJSON(badgeJSON: String): Message { val badgeConfig = getBadgeFromJSON(badgeJSON) - return DataToSend(listOf(Message( + return Message( Converters.fixLEDHex(badgeConfig.hexStrings, badgeConfig.isInverted), badgeConfig.isMarquee, badgeConfig.isFlash, badgeConfig.speed, badgeConfig.mode - ))) + ) } fun configToJSON(data: Message, invertLED: Boolean): String { diff --git a/android/src/main/java/org/fossasia/badgemagic/viewmodels/TransferQueueViewModel.kt b/android/src/main/java/org/fossasia/badgemagic/viewmodels/TransferQueueViewModel.kt new file mode 100644 index 00000000..60368bd6 --- /dev/null +++ b/android/src/main/java/org/fossasia/badgemagic/viewmodels/TransferQueueViewModel.kt @@ -0,0 +1,27 @@ +package org.fossasia.badgemagic.viewmodels + +import androidx.lifecycle.LiveData +import androidx.lifecycle.MutableLiveData +import androidx.lifecycle.ViewModel +import org.fossasia.badgemagic.data.Message + +class TransferQueueViewModel : ViewModel() { + private val _items = MutableLiveData>() + val items: LiveData> + get() = _items + + init { + _items.value = ArrayList() + } + + fun add(item: Message) { + _items.value?.add(item) + if (_items.value!!.size > 8) { + _items.value?.removeAt(0) + } + } + + fun remove(item: Message) { + _items.value?.remove(item) + } +} diff --git a/android/src/main/res/layout/fragment_transfer.xml b/android/src/main/res/layout/fragment_transfer.xml new file mode 100644 index 00000000..8da1384e --- /dev/null +++ b/android/src/main/res/layout/fragment_transfer.xml @@ -0,0 +1,91 @@ + + + + + + + + + + + + + + + + + + + + + + + + + +