diff --git a/app/build.gradle.kts b/app/build.gradle.kts index b58c5f76..32d77d4c 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -109,8 +109,6 @@ dependencies { implementation(libs.bundles.materialdialogs) - implementation(libs.bundles.groupie) - implementation(libs.draglinearlayout) implementation(libs.viewpropertyobjectanimator) diff --git a/base/src/main/java/de/mm20/launcher2/licenses/OpenSourceLicenses.kt b/base/src/main/java/de/mm20/launcher2/licenses/OpenSourceLicenses.kt index f0fbbfe6..cbdda6e9 100644 --- a/base/src/main/java/de/mm20/launcher2/licenses/OpenSourceLicenses.kt +++ b/base/src/main/java/de/mm20/launcher2/licenses/OpenSourceLicenses.kt @@ -100,13 +100,6 @@ val OpenSourceLicenses = arrayOf( copyrightNote = "Copyright (C) 2020 Wasabeef", url = "https://github.com/afollestad/material-dialogs" ), - OpenSourceLibrary( - name = "Groupie", - description = "Groupie is a simple, flexible library for complex RecyclerView layouts.", - licenseName = R.string.mit_license_name, - licenseText = R.raw.license_mit, - url = "https://github.com/lisawray/groupie" - ), OpenSourceLibrary( name = "DragLinearLayout", description = "An Android LinearLayout that supports draggable and swappable child Views", diff --git a/settings.gradle.kts b/settings.gradle.kts index 56594a24..cc1cd6f1 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -321,21 +321,6 @@ dependencyResolutionManagement { ) ) - version("groupie", "2.8.0") - alias("groupie.core") - .to("com.xwray", "groupie") - .versionRef("groupie") - alias("groupie.ktx") - .to("com.xwray", "groupie-kotlin-android-extensions") - .versionRef("groupie") - bundle( - "groupie", - listOf( - "groupie.core", - "groupie.ktx" - ) - ) - alias("draglinearlayout") .to("com.jmedeisis", "draglinearlayout") .version("1.1.0") diff --git a/ui/build.gradle.kts b/ui/build.gradle.kts index 5b1259cc..99047f15 100644 --- a/ui/build.gradle.kts +++ b/ui/build.gradle.kts @@ -71,7 +71,6 @@ dependencies { implementation(libs.glide) implementation(libs.draglinearlayout) implementation(libs.lottie.core) - implementation(libs.bundles.groupie) implementation(libs.glidetransformations) implementation(libs.accompanist.insets) diff --git a/ui/src/main/java/de/mm20/launcher2/ui/legacy/component/UnitConverterView.kt b/ui/src/main/java/de/mm20/launcher2/ui/legacy/component/UnitConverterView.kt index acfd17f4..21b169ae 100644 --- a/ui/src/main/java/de/mm20/launcher2/ui/legacy/component/UnitConverterView.kt +++ b/ui/src/main/java/de/mm20/launcher2/ui/legacy/component/UnitConverterView.kt @@ -1,49 +1,37 @@ package de.mm20.launcher2.ui.legacy.component import android.content.Context -import android.net.Uri -import android.text.SpannableStringBuilder -import android.text.Spanned -import android.text.method.LinkMovementMethod -import android.text.style.ClickableSpan import android.util.AttributeSet import android.view.LayoutInflater import android.view.View import android.widget.FrameLayout -import android.widget.TextView import androidx.appcompat.app.AppCompatActivity -import androidx.browser.customtabs.CustomTabsIntent +import androidx.compose.foundation.layout.Column +import androidx.compose.material3.LocalContentColor +import androidx.compose.material3.MaterialTheme +import androidx.compose.runtime.CompositionLocalProvider +import androidx.compose.runtime.getValue +import androidx.compose.runtime.livedata.observeAsState import androidx.lifecycle.LiveData import androidx.lifecycle.Observer -import androidx.recyclerview.widget.DividerItemDecoration -import androidx.recyclerview.widget.LinearLayoutManager -import com.afollestad.materialdialogs.MaterialDialog -import com.xwray.groupie.ExpandableGroup -import com.xwray.groupie.ExpandableItem -import com.xwray.groupie.GroupAdapter -import com.xwray.groupie.Section -import com.xwray.groupie.kotlinandroidextensions.GroupieViewHolder -import com.xwray.groupie.kotlinandroidextensions.Item -import de.mm20.launcher2.ktx.sp -import de.mm20.launcher2.search.data.CurrencyUnitConverter import de.mm20.launcher2.search.data.UnitConverter -import de.mm20.launcher2.ui.R +import de.mm20.launcher2.ui.LegacyLauncherTheme import de.mm20.launcher2.ui.databinding.ViewUnitconverterBinding +import de.mm20.launcher2.ui.search.UnitConverterItem import de.mm20.launcher2.unitconverter.UnitConverterViewModel -import de.mm20.launcher2.unitconverter.UnitValue import org.koin.androidx.viewmodel.ext.android.viewModel -import java.text.DateFormat -import java.util.* -import kotlin.math.min class UnitConverterView : FrameLayout { constructor(context: Context) : super(context) constructor(context: Context, attrs: AttributeSet?) : super(context, attrs) - constructor(context: Context, attrs: AttributeSet?, defStyleRes: Int) : super(context, attrs, defStyleRes) + constructor(context: Context, attrs: AttributeSet?, defStyleRes: Int) : super( + context, + attrs, + defStyleRes + ) private val unitConverter: LiveData - private val adapter: GroupAdapter private val binding = ViewUnitconverterBinding.inflate(LayoutInflater.from(context), this, true) @@ -54,141 +42,24 @@ class UnitConverterView : FrameLayout { if (it == null) visibility = View.GONE else { visibility = View.VISIBLE - bind(it) } }) - adapter = GroupAdapter() - binding.unitConverterValues.also { - it.adapter = adapter - it.addItemDecoration(DividerItemDecoration(context, LinearLayoutManager.VERTICAL)) - } - } - - private fun bind(converter: UnitConverter) { - val title = converter.inputValue.formattedValue + " " + converter.inputValue.formattedName - binding.unitConverterInput.text = title - - /*val sb = StringBuilder() - for (unit in converter.values) { - - sb.append("${unit.formatted}\n") - } - sb.removeSuffix("\n") - unitConverterValues.text = sb.toString() - unitConverterIcon.setImageResource(when (converter.dimension) { - Dimension.LENGTH -> R.drawable.ic_unit_length - Dimension.MASS -> R.drawable.ic_unit_mass - Dimension.TIME -> R.drawable.ic_unit_time - Dimension.DATA -> R.drawable.ic_unit_datasize - Dimension.VELOCITY -> R.drawable.ic_unit_velocity - else -> 0 - })*/ - - adapter.clear() - - val maxValueLength = converter.values.maxByOrNull { it.formattedValue.length }?.formattedValue?.length - ?: 0 - - val section = Section().apply { - addAll(converter.values.subList(0, min(converter.values.size, 5)).map { - ValueItem(it, maxValueLength * 8f * sp) - }) - }.also { - adapter.add(it) - } - - if (converter.values.size > 5) { - binding.showAllButton.visibility = View.VISIBLE - binding.showAllButton.setOnClickListener { - section.addAll(converter.values.subList( 5, converter.values.size).map { - ValueItem(it, maxValueLength * 8f * sp) - }) - binding.showAllButton.visibility = View.GONE - binding.showAllButton.setOnClickListener(null) - } - } else { - binding.showAllButton.visibility = View.GONE - } - - - if (converter is CurrencyUnitConverter) { - val df = DateFormat.getDateInstance(DateFormat.SHORT) - val date = Date().apply { - time = converter.updateTimestamp - } - val infoText = SpannableStringBuilder() - .append("European Central Bank (${df.format(date)})", object : ClickableSpan() { - override fun onClick(widget: View) { - CustomTabsIntent - .Builder() - .setToolbarColor(0xFF003299.toInt()) - .build() - .launchUrl(context, - Uri.parse("https://www.ecb.europa.eu/stats/policy_and_exchange_rates/euro_reference_exchange_rates/html/index.en.html")) + binding.composeView.setContent { + val converter by unitConverter.observeAsState() + LegacyLauncherTheme { + // TODO: Temporary solution until parent widget card is rewritten in Compose + CompositionLocalProvider(LocalContentColor provides MaterialTheme.colorScheme.onSurface) { + Column { + converter?.let { + UnitConverterItem( + unitConverter = it, + ) } - }, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE) - .append(" • ") - .append(context.getString(R.string.disclaimer), object : ClickableSpan() { - override fun onClick(widget: View) { - MaterialDialog(context).show { - title(res = R.string.disclaimer) - message(res = R.string.disclaimer_currency_converter) - positiveButton(res = R.string.close) { - dismiss() - } - } - } - }, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE) - - binding.unitConverterInfo.apply { - text = infoText - visibility = View.VISIBLE - movementMethod = LinkMovementMethod.getInstance() - } - } else { - binding.unitConverterInfo.visibility = View.GONE - } - - } -} - -class ValueItem(private val value: UnitValue, val valueWidth: Float) : Item() { - override fun getLayout(): Int { - return R.layout.unit_converter_row - } - - override fun bind(viewHolder: GroupieViewHolder, position: Int) { - viewHolder.itemView.findViewById(R.id.value).let { - it.text = value.formattedValue - it.layoutParams = it.layoutParams.apply { - width = valueWidth.toInt() + } + } } } - viewHolder.itemView.findViewById(R.id.name).text = value.formattedName - viewHolder.itemView.findViewById(R.id.symbol).text = value.symbol - } - -} - -class ExpandItem : Item(), ExpandableItem { - - private lateinit var expandableGroup: ExpandableGroup - - override fun bind(viewHolder: GroupieViewHolder, position: Int) { - viewHolder.itemView.visibility = if (expandableGroup.isExpanded) View.GONE else View.VISIBLE - viewHolder.itemView.setOnClickListener { - expandableGroup.onToggleExpanded() - viewHolder.itemView.visibility = View.GONE - } - } - - override fun getLayout(): Int { - return R.layout.unit_converter_show_all - } - - override fun setExpandableGroup(onToggleListener: ExpandableGroup) { - expandableGroup = onToggleListener } } \ No newline at end of file diff --git a/ui/src/main/java/de/mm20/launcher2/ui/search/UnitConverterItem.kt b/ui/src/main/java/de/mm20/launcher2/ui/search/UnitConverterItem.kt new file mode 100644 index 00000000..2275f7f9 --- /dev/null +++ b/ui/src/main/java/de/mm20/launcher2/ui/search/UnitConverterItem.kt @@ -0,0 +1,121 @@ +package de.mm20.launcher2.ui.search + +import androidx.compose.foundation.layout.* +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.rounded.* +import androidx.compose.material3.* +import androidx.compose.runtime.* +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.vector.ImageVector +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.text.AnnotatedString +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.text.style.TextOverflow +import androidx.compose.ui.unit.dp +import de.mm20.launcher2.search.data.UnitConverter +import de.mm20.launcher2.ui.R +import de.mm20.launcher2.unitconverter.Dimension + +@Composable +fun UnitConverterItem( + unitConverter: UnitConverter, +) { + var showAll by remember { mutableStateOf(false) } + Column( + modifier = Modifier.padding(bottom = 8.dp) + ) { + Row( + verticalAlignment = Alignment.CenterVertically + ) { + Text( + text = unitConverter.inputValue.let { "${it.formattedValue} ${it.formattedName}" }, + style = MaterialTheme.typography.headlineSmall, + modifier = Modifier + .weight(1f) + .padding(horizontal = 16.dp), + overflow = TextOverflow.Ellipsis, + softWrap = false + ) + Surface( + modifier = Modifier + .padding(12.dp) + .size(48.dp), + color = MaterialTheme.colorScheme.primaryContainer, + shape = RoundedCornerShape(8.dp) + ) { + Box( + contentAlignment = Alignment.Center + ) { + Icon( + imageVector = getDimensionIcon(unitConverter.dimension), + contentDescription = null, + tint = MaterialTheme.colorScheme.primary, + modifier = Modifier.size(24.dp) + ) + } + } + } + Row { + Column { + for ((i, unit) in unitConverter.values.withIndex()) { + if (!showAll && i >= 5) break + Text( + text = unit.formattedValue, + style = MaterialTheme.typography.bodyMedium.copy( + fontWeight = FontWeight.Bold + ), + modifier = Modifier + .padding(start = 16.dp, bottom = 12.dp) + ) + } + + + } + Column { + for ((i, unit) in unitConverter.values.withIndex()) { + if (!showAll && i >= 5) break + val text = AnnotatedString.Builder().apply { + append(" ${unit.formattedName} (${unit.symbol})") + }.toAnnotatedString() + Text( + text = "${unit.formattedName} (${unit.symbol})", + style = MaterialTheme.typography.bodyMedium, + modifier = Modifier + .padding(end = 16.dp, bottom = 12.dp, start = 8.dp) + ) + } + } + + } + if (!showAll && unitConverter.values.size > 5) { + TextButton( + onClick = { showAll = true }, + modifier = Modifier + .align(Alignment.End) + .padding(horizontal = 12.dp) + ) { + Text(text = stringResource(id = R.string.unit_converter_show_all)) + } + } + } +} + +fun getDimensionIcon(dimension: Dimension): ImageVector { + return when (dimension) { + Dimension.Mass -> Icons.Rounded.FitnessCenter + Dimension.Length -> Icons.Rounded.Straighten + Dimension.Velocity -> Icons.Rounded.Speed + Dimension.Volume -> TODO() + Dimension.Area -> Icons.Rounded.SquareFoot + Dimension.Currency -> Icons.Rounded.Toll + Dimension.Data -> Icons.Rounded.Storage + Dimension.Bitrate -> TODO() + Dimension.Pressure -> TODO() + Dimension.Energy -> Icons.Rounded.Bolt + Dimension.Frequency -> TODO() + Dimension.Temperature -> Icons.Rounded.Thermostat + Dimension.Time -> Icons.Rounded.Schedule + } +} \ No newline at end of file diff --git a/ui/src/main/res/layout/view_unitconverter.xml b/ui/src/main/res/layout/view_unitconverter.xml index 875f5c5e..f24fb628 100644 --- a/ui/src/main/res/layout/view_unitconverter.xml +++ b/ui/src/main/res/layout/view_unitconverter.xml @@ -10,89 +10,9 @@ android:clipToPadding="false" android:elevation="@dimen/card_elevation"> - - - - - - - - - - - - - - + android:layout_height="wrap_content"/> \ No newline at end of file