Fix miscellaneous inspections

pull/2437/head
Alex Baker 9 months ago
parent 804c0f974a
commit 427ee369b4

@ -2,12 +2,22 @@ package org.tasks.billing
import android.app.Activity import android.app.Activity
import android.content.Context import android.content.Context
import com.android.billingclient.api.* import com.android.billingclient.api.AcknowledgePurchaseParams
import com.android.billingclient.api.BillingClient.* import com.android.billingclient.api.BillingClient.BillingResponseCode
import com.android.billingclient.api.BillingClient.SkuType
import com.android.billingclient.api.BillingClient.newBuilder
import com.android.billingclient.api.BillingClientStateListener
import com.android.billingclient.api.BillingFlowParams
import com.android.billingclient.api.BillingFlowParams.ProrationMode import com.android.billingclient.api.BillingFlowParams.ProrationMode
import com.android.billingclient.api.BillingFlowParams.SubscriptionUpdateParams import com.android.billingclient.api.BillingFlowParams.SubscriptionUpdateParams
import com.android.billingclient.api.BillingResult
import com.android.billingclient.api.ConsumeParams
import com.android.billingclient.api.Purchase.PurchaseState import com.android.billingclient.api.Purchase.PurchaseState
import com.android.billingclient.api.Purchase.PurchasesResult import com.android.billingclient.api.Purchase.PurchasesResult
import com.android.billingclient.api.PurchasesUpdatedListener
import com.android.billingclient.api.SkuDetailsParams
import com.android.billingclient.api.consumePurchase
import com.android.billingclient.api.querySkuDetails
import dagger.hilt.android.qualifiers.ApplicationContext import dagger.hilt.android.qualifiers.ApplicationContext
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.NonCancellable import kotlinx.coroutines.NonCancellable
@ -125,7 +135,7 @@ class BillingClientImpl(
.setPurchaseToken(purchase.purchaseToken) .setPurchaseToken(purchase.purchaseToken)
.build() .build()
withContext(Dispatchers.IO) { withContext(Dispatchers.IO) {
suspendCoroutine<BillingResult> { cont -> suspendCoroutine { cont ->
billingClient.acknowledgePurchase(params) { billingClient.acknowledgePurchase(params) {
Timber.d("acknowledge: ${it.responseCodeString} $purchase") Timber.d("acknowledge: ${it.responseCodeString} $purchase")
cont.resume(it) cont.resume(it)

@ -28,7 +28,7 @@ package org.tasks.billing
* by implementing security measure X is greater than the money you would lose if you don't * by implementing security measure X is greater than the money you would lose if you don't
* implement X. Talk to a UX designer if you find yourself obsessing over security. * implement X. Talk to a UX designer if you find yourself obsessing over security.
* *
* The good news is, in implementing [BillingRepository], a number of measures is taken to help * The good news is, in implementing BillingRepository, a number of measures is taken to help
* prevent fraudulent activities in your app. We don't just focus on tech savvy hackers, but also * prevent fraudulent activities in your app. We don't just focus on tech savvy hackers, but also
* on fraudulent users who may want to exploit loopholes. Just to name an obvious case: * on fraudulent users who may want to exploit loopholes. Just to name an obvious case:
* triangulation using Google Play, your secure server, and a local cache helps against non-techie * triangulation using Google Play, your secure server, and a local cache helps against non-techie

@ -36,7 +36,7 @@ class GoogleMapFragment @Inject constructor(
} }
override val mapPosition: MapPosition? override val mapPosition: MapPosition?
get() = map?.cameraPosition?.let { it -> get() = map?.cameraPosition?.let {
val target = it.target val target = it.target
return MapPosition(target.latitude, target.longitude, it.zoom) return MapPosition(target.latitude, target.longitude, it.zoom)
} }

@ -14,7 +14,6 @@ class Operator private constructor(private val operator: String) {
val `in` = Operator("IN") val `in` = Operator("IN")
val exists = Operator("EXISTS") val exists = Operator("EXISTS")
val gt = Operator(">") val gt = Operator(">")
val gte = Operator(">=")
val lt = Operator("<") val lt = Operator("<")
val lte = Operator("<=") val lte = Operator("<=")
} }

@ -19,8 +19,6 @@ open class UnaryCriterion private constructor(private val expression: Field, ope
fun gt(field: Field, value: Any?): Criterion = UnaryCriterion(field, Operator.gt, value) fun gt(field: Field, value: Any?): Criterion = UnaryCriterion(field, Operator.gt, value)
fun gte(field: Field, value: Any?): Criterion = UnaryCriterion(field, Operator.gte, value)
fun lt(field: Field, value: Any?): Criterion = UnaryCriterion(field, Operator.lt, value) fun lt(field: Field, value: Any?): Criterion = UnaryCriterion(field, Operator.lt, value)
fun lte(field: Field, value: Any?): Criterion = UnaryCriterion(field, Operator.lte, value) fun lte(field: Field, value: Any?): Criterion = UnaryCriterion(field, Operator.lte, value)

@ -306,11 +306,11 @@ class TaskListFragment : Fragment(), OnRefreshListener, Toolbar.OnMenuItemClickL
setupRefresh(swipeRefreshLayout) setupRefresh(swipeRefreshLayout)
setupRefresh(emptyRefreshLayout) setupRefresh(emptyRefreshLayout)
binding.toolbar.title = filter.listingTitle binding.toolbar.title = filter.listingTitle
binding.appbarlayout.addOnOffsetChangedListener(AppBarLayout.OnOffsetChangedListener { _, verticalOffset -> binding.appbarlayout.addOnOffsetChangedListener { _, verticalOffset ->
if (verticalOffset == 0 && binding.bottomAppBar.isScrolledDown) { if (verticalOffset == 0 && binding.bottomAppBar.isScrolledDown) {
binding.bottomAppBar.performShow() binding.bottomAppBar.performShow()
} }
}) }
val toolbar = if (preferences.isTopAppBar) { val toolbar = if (preferences.isTopAppBar) {
binding.bottomAppBar.isVisible = false binding.bottomAppBar.isVisible = false
with (binding.fab) { with (binding.fab) {
@ -639,7 +639,7 @@ class TaskListFragment : Fragment(), OnRefreshListener, Toolbar.OnMenuItemClickL
VOICE_RECOGNITION_REQUEST_CODE -> if (resultCode == Activity.RESULT_OK) { VOICE_RECOGNITION_REQUEST_CODE -> if (resultCode == Activity.RESULT_OK) {
lifecycleScope.launch { lifecycleScope.launch {
val match: List<String>? = data!!.getStringArrayListExtra(RecognizerIntent.EXTRA_RESULTS) val match: List<String>? = data!!.getStringArrayListExtra(RecognizerIntent.EXTRA_RESULTS)
if (match != null && match.isNotEmpty() && match[0].isNotEmpty()) { if (!match.isNullOrEmpty() && match[0].isNotEmpty()) {
var recognizedSpeech = match[0] var recognizedSpeech = match[0]
recognizedSpeech = (recognizedSpeech.substring(0, 1) recognizedSpeech = (recognizedSpeech.substring(0, 1)
.uppercase(Locale.getDefault()) .uppercase(Locale.getDefault())

@ -192,7 +192,7 @@ open class TaskAdapter(
return false return false
} }
internal fun findParent(indent: Int, to: Int): TaskContainer? { private fun findParent(indent: Int, to: Int): TaskContainer? {
if (indent == 0 || to == 0) { if (indent == 0 || to == 0) {
return null return null
} }

@ -3,7 +3,7 @@ package com.todoroo.astrid.api
import android.os.Parcel import android.os.Parcel
import android.os.Parcelable import android.os.Parcelable
class BooleanCriterion constructor() : CustomFilterCriterion(), Parcelable { class BooleanCriterion() : CustomFilterCriterion(), Parcelable {
constructor(identifier: String, title: String, sql: String): this() { constructor(identifier: String, title: String, sql: String): this() {
this.identifier = identifier this.identifier = identifier

@ -7,7 +7,12 @@ import com.todoroo.andlib.sql.Join
import com.todoroo.andlib.sql.Query import com.todoroo.andlib.sql.Query
import com.todoroo.andlib.sql.QueryTemplate import com.todoroo.andlib.sql.QueryTemplate
import com.todoroo.astrid.data.Task import com.todoroo.astrid.data.Task
import org.tasks.data.* import org.tasks.data.CaldavCalendar
import org.tasks.data.CaldavTask
import org.tasks.data.Geofence
import org.tasks.data.Place
import org.tasks.data.Tag
import org.tasks.data.UserActivity
class SearchFilter : Filter { class SearchFilter : Filter {
private constructor() private constructor()
@ -21,7 +26,7 @@ class SearchFilter : Filter {
@JvmField @JvmField
val CREATOR: Parcelable.Creator<SearchFilter> = object : Parcelable.Creator<SearchFilter> { val CREATOR: Parcelable.Creator<SearchFilter> = object : Parcelable.Creator<SearchFilter> {
/** {@inheritDoc} */ /** {@inheritDoc} */
override fun createFromParcel(source: Parcel): SearchFilter? { override fun createFromParcel(source: Parcel): SearchFilter {
val item = SearchFilter() val item = SearchFilter()
item.readFromParcel(source) item.readFromParcel(source)
return item return item

@ -34,20 +34,27 @@ class CriterionInstance {
// $NON-NLS-1$ // $NON-NLS-1$
val titleFromCriterion: String val titleFromCriterion: String
get() { get() {
if (criterion is MultipleSelectCriterion) { when (criterion) {
if (selectedIndex >= 0 && (criterion as MultipleSelectCriterion).entryTitles != null && selectedIndex < (criterion as MultipleSelectCriterion).entryTitles.size) { is MultipleSelectCriterion -> {
val title = (criterion as MultipleSelectCriterion).entryTitles[selectedIndex] if (selectedIndex >= 0 && (criterion as MultipleSelectCriterion).entryTitles != null && selectedIndex < (criterion as MultipleSelectCriterion).entryTitles.size) {
return criterion.text.replace("?", title) val title = (criterion as MultipleSelectCriterion).entryTitles[selectedIndex]
return criterion.text.replace("?", title)
}
return criterion.text
} }
return criterion.text
} else if (criterion is TextInputCriterion) { is TextInputCriterion -> {
return if (selectedText == null) { return if (selectedText == null) {
criterion.text criterion.text
} else criterion.text.replace("?", selectedText!!) } else criterion.text.replace("?", selectedText!!)
} else if (criterion is BooleanCriterion) { }
return criterion.name
is BooleanCriterion -> {
return criterion.name
}
// $NON-NLS-1$
else -> throw UnsupportedOperationException("Unknown criterion type")
} }
throw UnsupportedOperationException("Unknown criterion type") // $NON-NLS-1$
} }
// $NON-NLS-1$ // $NON-NLS-1$
@ -56,16 +63,23 @@ class CriterionInstance {
if (type == TYPE_UNIVERSE) { if (type == TYPE_UNIVERSE) {
return null return null
} }
if (criterion is MultipleSelectCriterion) { when (criterion) {
return if (selectedIndex >= 0 && (criterion as MultipleSelectCriterion).entryValues != null && selectedIndex < (criterion as MultipleSelectCriterion).entryValues.size) { is MultipleSelectCriterion -> {
(criterion as MultipleSelectCriterion).entryValues[selectedIndex] return if (selectedIndex >= 0 && (criterion as MultipleSelectCriterion).entryValues != null && selectedIndex < (criterion as MultipleSelectCriterion).entryValues.size) {
} else criterion.text (criterion as MultipleSelectCriterion).entryValues[selectedIndex]
} else if (criterion is TextInputCriterion) { } else criterion.text
return selectedText }
} else if (criterion is BooleanCriterion) {
return criterion.name is TextInputCriterion -> {
return selectedText
}
is BooleanCriterion -> {
return criterion.name
}
// $NON-NLS-1$
else -> throw UnsupportedOperationException("Unknown criterion type")
} }
throw UnsupportedOperationException("Unknown criterion type") // $NON-NLS-1$
} }
private fun serialize(): String { private fun serialize(): String {

@ -112,8 +112,8 @@ class TaskDao @Inject constructor(
} }
private suspend fun afterUpdate(task: Task, original: Task?) { private suspend fun afterUpdate(task: Task, original: Task?) {
val completionDateModified = task.completionDate != original?.completionDate ?: 0 val completionDateModified = task.completionDate != (original?.completionDate ?: 0)
val deletionDateModified = task.deletionDate != original?.deletionDate ?: 0 val deletionDateModified = task.deletionDate != (original?.deletionDate ?: 0)
val justCompleted = completionDateModified && task.isCompleted val justCompleted = completionDateModified && task.isCompleted
val justDeleted = deletionDateModified && task.isDeleted val justDeleted = deletionDateModified && task.isDeleted
if (task.calendarURI?.isNotBlank() == true) { if (task.calendarURI?.isNotBlank() == true) {

@ -121,8 +121,7 @@ class Astrid2TaskProvider : ContentProvider() {
} }
private fun tagNameToLong(tag: String?): Long { private fun tagNameToLong(tag: String?): Long {
val m: MessageDigest val m: MessageDigest = try {
m = try {
MessageDigest.getInstance("MD5") MessageDigest.getInstance("MD5")
} catch (e: NoSuchAlgorithmException) { } catch (e: NoSuchAlgorithmException) {
Timber.e(e) Timber.e(e)
@ -173,7 +172,8 @@ class Astrid2TaskProvider : ContentProvider() {
projection: Array<String>?, projection: Array<String>?,
selection: String?, selection: String?,
selectionArgs: Array<String>?, selectionArgs: Array<String>?,
sortOrder: String?): Cursor? { sortOrder: String?
): Cursor {
return when (URI_MATCHER.match(uri)) { return when (URI_MATCHER.match(uri)) {
URI_TASKS -> tasks URI_TASKS -> tasks
URI_TAGS -> tags URI_TAGS -> tags

@ -75,7 +75,7 @@ class RepeatTaskHelper @Inject constructor(
val previousDueDate = val previousDueDate =
oldDueDate oldDueDate
.takeIf { it > 0 } .takeIf { it > 0 }
?: newDueDate - (computeNextDueDate(task, recurrence, repeatAfterCompletion) - newDueDate) ?: (newDueDate - (computeNextDueDate(task, recurrence, repeatAfterCompletion) - newDueDate))
rescheduleAlarms(task.id, previousDueDate, newDueDate) rescheduleAlarms(task.id, previousDueDate, newDueDate)
taskCompleter.setComplete(task, false) taskCompleter.setComplete(task, false)
broadcastCompletion(task, previousDueDate) broadcastCompletion(task, previousDueDate)

@ -353,8 +353,7 @@ class SubtasksFilterUpdater @Inject constructor(
node: Node, children: JSONArray, callback: ((Node?) -> Unit)?) { node: Node, children: JSONArray, callback: ((Node?) -> Unit)?) {
for (i in 1 until children.length()) { for (i in 1 until children.length()) {
val subarray = children.optJSONArray(i) val subarray = children.optJSONArray(i)
var uuid: String val uuid: String = if (subarray == null) {
uuid = if (subarray == null) {
children.getString(i) children.getString(i)
} else { } else {
subarray.getString(0) subarray.getString(0)

@ -14,7 +14,8 @@ import org.tasks.Strings.isNullOrEmpty
import org.tasks.data.TagDataDao import org.tasks.data.TagDataDao
import org.tasks.repeats.RecurrenceUtils.newRecur import org.tasks.repeats.RecurrenceUtils.newRecur
import timber.log.Timber import timber.log.Timber
import java.util.* import java.util.Calendar
import java.util.Locale
import java.util.regex.Matcher import java.util.regex.Matcher
import java.util.regex.Pattern import java.util.regex.Pattern
@ -403,7 +404,7 @@ object TitleParser {
) )
for (i in words.indices) { for (i in words.indices) {
wordsToNum[words[i]] = i + 1 wordsToNum[words[i]] = i + 1
wordsToNum[Integer.toString(i + 1)] = i + 1 wordsToNum[(i + 1).toString()] = i + 1
} }
wordsToNum["other"] = 2 wordsToNum["other"] = 2
val pattern = Pattern.compile("(?i)\\bevery (\\w*)\\b") val pattern = Pattern.compile("(?i)\\bevery (\\w*)\\b")

@ -69,7 +69,7 @@ class Notifier @Inject constructor(
.setGroupSummary(true) .setGroupSummary(true)
.setGroup(filter.listingTitle) .setGroup(filter.listingTitle)
.setStyle(style) .setStyle(style)
notificationManager.notify(filter.listingTitle.hashCode().toLong(), builder, true, false, false) notificationManager.notify(filter.listingTitle.hashCode().toLong(), builder, alert = true, nonstop = false, fiveTimes = false)
} }
suspend fun triggerNotifications(place: Long, geofences: List<Geofence>, arrival: Boolean) = suspend fun triggerNotifications(place: Long, geofences: List<Geofence>, arrival: Boolean) =

@ -16,7 +16,7 @@ import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.flow.scan import kotlinx.coroutines.flow.scan
import java.util.* import java.util.Queue
interface DragAndDropDiffer<T, R> : ListUpdateCallback { interface DragAndDropDiffer<T, R> : ListUpdateCallback {
val channel: Channel<List<T>> val channel: Channel<List<T>>
@ -58,10 +58,10 @@ interface DragAndDropDiffer<T, R> : ListUpdateCallback {
channel channel
.consumeAsFlow() .consumeAsFlow()
.map { transform(it) } .map { transform(it) }
.scan(Pair(initial, null), { last: Pair<R, DiffUtil.DiffResult?>, next: R -> .scan(Pair(initial, null)) { last: Pair<R, DiffUtil.DiffResult?>, next: R ->
calculateDiff(last, next) calculateDiff(last, next)
}) }
.drop(1) .drop(1)
.flowOn(Dispatchers.Default) .flowOn(Dispatchers.Default)
.onEach { applyDiff(it) } .onEach { applyDiff(it) }
.launchIn(CoroutineScope(Dispatchers.Main + Job())) .launchIn(CoroutineScope(Dispatchers.Main + Job()))

@ -78,7 +78,7 @@ class GoogleTaskListSettingsActivity : BaseListSettingsActivity() {
override val isNew: Boolean override val isNew: Boolean
get() = isNewList get() = isNewList
override val toolbarTitle: String? override val toolbarTitle: String
get() = if (isNew) getString(R.string.new_list) else gtasksList.name!! get() = if (isNew) getString(R.string.new_list) else gtasksList.name!!
private fun showProgressIndicator() { private fun showProgressIndicator() {

@ -6,12 +6,19 @@ import android.net.Uri
import androidx.browser.customtabs.CustomTabsIntent import androidx.browser.customtabs.CustomTabsIntent
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext import kotlinx.coroutines.withContext
import net.openid.appauth.* import net.openid.appauth.AppAuthConfiguration
import net.openid.appauth.AuthorizationException
import net.openid.appauth.AuthorizationRequest
import net.openid.appauth.AuthorizationService import net.openid.appauth.AuthorizationService
import net.openid.appauth.ClientAuthentication
import net.openid.appauth.RegistrationRequest
import net.openid.appauth.RegistrationResponse
import net.openid.appauth.TokenRequest
import net.openid.appauth.TokenResponse
import net.openid.appauth.browser.AnyBrowserMatcher import net.openid.appauth.browser.AnyBrowserMatcher
import kotlin.coroutines.suspendCoroutine import kotlin.coroutines.suspendCoroutine
class AuthorizationService constructor( class AuthorizationService(
val iss: String, val iss: String,
context: Context, context: Context,
debugConnectionBuilder: DebugConnectionBuilder debugConnectionBuilder: DebugConnectionBuilder

@ -34,7 +34,7 @@ import java.nio.charset.StandardCharsets
* changes are detected by comparing the hash of the last known configuration to the read * changes are detected by comparing the hash of the last known configuration to the read
* configuration. When a configuration change is detected, the app state is reset. * configuration. When a configuration change is detected, the app state is reset.
*/ */
class Configuration constructor( class Configuration(
private val context: Context, private val context: Context,
private val authConfig: Int, private val authConfig: Int,
debugConnectionBuilder: DebugConnectionBuilder debugConnectionBuilder: DebugConnectionBuilder

@ -20,8 +20,6 @@ import dagger.hilt.android.qualifiers.ApplicationContext
import net.openid.appauth.Preconditions import net.openid.appauth.Preconditions
import net.openid.appauth.connectivity.ConnectionBuilder import net.openid.appauth.connectivity.ConnectionBuilder
import okhttp3.internal.tls.OkHostnameVerifier import okhttp3.internal.tls.OkHostnameVerifier
import org.tasks.DebugNetworkInterceptor
import org.tasks.preferences.Preferences
import java.io.IOException import java.io.IOException
import java.net.HttpURLConnection import java.net.HttpURLConnection
import java.net.URL import java.net.URL
@ -36,11 +34,9 @@ import javax.net.ssl.SSLContext
*/ */
class DebugConnectionBuilder @Inject constructor( class DebugConnectionBuilder @Inject constructor(
@ApplicationContext private val context: Context, @ApplicationContext private val context: Context,
private val interceptor: DebugNetworkInterceptor,
private val preferences: Preferences,
) : ConnectionBuilder { ) : ConnectionBuilder {
var appInForeground: Boolean = true private var appInForeground: Boolean = true
@Throws(IOException::class) @Throws(IOException::class)
override fun openConnection(uri: Uri): HttpURLConnection { override fun openConnection(uri: Uri): HttpURLConnection {

@ -9,7 +9,7 @@ import okhttp3.OkHttpClient
import okhttp3.Request import okhttp3.Request
import org.json.JSONObject import org.json.JSONObject
class TasksClient constructor( class TasksClient(
provider: CaldavClientProvider, provider: CaldavClientProvider,
httpClient: OkHttpClient, httpClient: OkHttpClient,
private val httpUrl: HttpUrl? private val httpUrl: HttpUrl?

@ -220,7 +220,7 @@ class iCalendar @Inject constructor(
task.applyRemote(remote, local) task.applyRemote(remote, local)
caldavTask.applyRemote(remote, local) caldavTask.applyRemote(remote, local)
if (remote.lastAck ?: 0 > task.reminderLast) { if ((remote.lastAck ?: 0) > task.reminderLast) {
notificationManager.cancel(task.id) notificationManager.cancel(task.id)
} }

@ -6,7 +6,14 @@ import androidx.compose.foundation.BorderStroke
import androidx.compose.foundation.clickable import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.defaultMinSize import androidx.compose.foundation.layout.defaultMinSize
import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.size
import androidx.compose.material.* import androidx.compose.material.ChipDefaults
import androidx.compose.material.ContentAlpha
import androidx.compose.material.ExperimentalMaterialApi
import androidx.compose.material.FilterChip
import androidx.compose.material.Icon
import androidx.compose.material.LocalMinimumInteractiveComponentEnforcement
import androidx.compose.material.MaterialTheme
import androidx.compose.material.Text
import androidx.compose.material.icons.Icons import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.outlined.Cancel import androidx.compose.material.icons.outlined.Cancel
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
@ -55,7 +62,7 @@ fun Chip(
clear: (() -> Unit)? = null, clear: (() -> Unit)? = null,
) { ) {
CompositionLocalProvider( CompositionLocalProvider(
LocalMinimumTouchTargetEnforcement provides false LocalMinimumInteractiveComponentEnforcement provides false
) { ) {
FilterChip( FilterChip(
selected = false, selected = false,

@ -44,7 +44,7 @@ fun OutlinedSpinner(
DropdownMenu( DropdownMenu(
expanded = expanded, expanded = expanded,
onDismissRequest = { expanded = false }, onDismissRequest = { expanded = false },
offset = DpOffset(-8.dp, 0.dp), offset = DpOffset((-8).dp, 0.dp),
) { ) {
options.forEachIndexed { index, item -> options.forEachIndexed { index, item ->
DropdownMenuItem( DropdownMenuItem(

@ -2,8 +2,19 @@ package org.tasks.compose.edit
import android.content.res.Configuration import android.content.res.Configuration
import androidx.compose.foundation.isSystemInDarkTheme import androidx.compose.foundation.isSystemInDarkTheme
import androidx.compose.foundation.layout.* import androidx.compose.foundation.layout.Arrangement
import androidx.compose.material.* import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.RowScope
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.wrapContentHeight
import androidx.compose.material.ExperimentalMaterialApi
import androidx.compose.material.LocalMinimumInteractiveComponentEnforcement
import androidx.compose.material.MaterialTheme
import androidx.compose.material.RadioButton
import androidx.compose.material.RadioButtonDefaults
import androidx.compose.material.Text
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.CompositionLocalProvider import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
@ -88,7 +99,7 @@ fun RowScope.PriorityButton(
) )
) )
CompositionLocalProvider( CompositionLocalProvider(
LocalMinimumTouchTargetEnforcement provides false, LocalMinimumInteractiveComponentEnforcement provides false,
) { ) {
RadioButton( RadioButton(
selected = priority == selected, selected = priority == selected,

@ -2,7 +2,12 @@ package org.tasks.data
import androidx.core.util.Pair import androidx.core.util.Pair
import androidx.lifecycle.LiveData import androidx.lifecycle.LiveData
import androidx.room.* import androidx.room.Dao
import androidx.room.Delete
import androidx.room.Insert
import androidx.room.Query
import androidx.room.Transaction
import androidx.room.Update
import com.todoroo.astrid.api.FilterListItem.NO_ORDER import com.todoroo.astrid.api.FilterListItem.NO_ORDER
import com.todoroo.astrid.data.Task import com.todoroo.astrid.data.Task
import com.todoroo.astrid.helper.UUIDHelper import com.todoroo.astrid.helper.UUIDHelper
@ -10,8 +15,6 @@ import org.tasks.db.DbUtils
import org.tasks.filters.AlphanumComparator import org.tasks.filters.AlphanumComparator
import org.tasks.filters.TagFilters import org.tasks.filters.TagFilters
import org.tasks.time.DateTimeUtils.currentTimeMillis import org.tasks.time.DateTimeUtils.currentTimeMillis
import java.util.*
import kotlin.collections.HashSet
@Dao @Dao
abstract class TagDataDao { abstract class TagDataDao {
@ -25,7 +28,7 @@ abstract class TagDataDao {
* If a tag already exists in the database that case insensitively matches the given tag, return * If a tag already exists in the database that case insensitively matches the given tag, return
* that. Otherwise, return the argument * that. Otherwise, return the argument
*/ */
suspend fun getTagWithCase(tag: String): String? = getTagByName(tag)?.name ?: tag suspend fun getTagWithCase(tag: String): String = getTagByName(tag)?.name ?: tag
suspend fun searchTags(query: String): List<TagData> = searchTagsInternal("%$query%").sort() suspend fun searchTags(query: String): List<TagData> = searchTagsInternal("%$query%").sort()

@ -107,7 +107,11 @@ class DateTimePicker : BaseDateTimePicker() {
} }
} }
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View {
binding = DialogDateTimePickerBinding.inflate(theme.getLayoutInflater(requireContext())) binding = DialogDateTimePickerBinding.inflate(theme.getLayoutInflater(requireContext()))
setupShortcutsAndCalendar() setupShortcutsAndCalendar()
with (binding.shortcuts) { with (binding.shortcuts) {
@ -206,7 +210,7 @@ class DateTimePicker : BaseDateTimePicker() {
private fun currentDate() = returnDate(day = customDate) private fun currentDate() = returnDate(day = customDate)
private fun currentTime() = returnSelectedTime(customTime) private fun currentTime() = returnSelectedTime(customTime)
fun pickTime() { private fun pickTime() {
val time = if (selectedTime == MULTIPLE_TIMES val time = if (selectedTime == MULTIPLE_TIMES
|| !Task.hasDueTime(today.withMillisOfDay(selectedTime).millis)) { || !Task.hasDueTime(today.withMillisOfDay(selectedTime).millis)) {
today.noon().millisOfDay today.noon().millisOfDay

@ -60,7 +60,7 @@ class Linkify @Inject constructor(
} }
} }
private inner class ClickHandlingURLSpan constructor( private inner class ClickHandlingURLSpan(
url: String?, url: String?,
private val linkClickHandler: ((String) -> Boolean), private val linkClickHandler: ((String) -> Boolean),
private val rowClickHandler: (() -> Unit), private val rowClickHandler: (() -> Unit),

@ -1,15 +1,11 @@
package org.tasks.dialogs package org.tasks.dialogs
import android.app.Dialog import android.app.Dialog
import android.content.Intent
import android.os.Bundle import android.os.Bundle
import android.text.method.LinkMovementMethod import android.text.method.LinkMovementMethod
import androidx.fragment.app.DialogFragment import androidx.fragment.app.DialogFragment
import dagger.hilt.android.AndroidEntryPoint import dagger.hilt.android.AndroidEntryPoint
import org.tasks.R
import org.tasks.billing.PurchaseActivity
import org.tasks.databinding.DialogWhatsNewBinding import org.tasks.databinding.DialogWhatsNewBinding
import org.tasks.extensions.Context.openUri
import org.tasks.markdown.MarkdownProvider import org.tasks.markdown.MarkdownProvider
import java.io.BufferedReader import java.io.BufferedReader
import javax.inject.Inject import javax.inject.Inject
@ -38,14 +34,4 @@ class WhatsNewDialog : DialogFragment() {
.setView(binding.root) .setView(binding.root)
.show() .show()
} }
private fun onSubscribeClick() {
dismiss()
startActivity(Intent(context, PurchaseActivity::class.java))
}
private fun onDonateClick() {
dismiss()
context?.openUri(R.string.url_donate)
}
} }

@ -51,7 +51,7 @@ object Context {
fun Context.toast(text: String?, duration: Int = Toast.LENGTH_LONG) = fun Context.toast(text: String?, duration: Int = Toast.LENGTH_LONG) =
text?.let { Toast.makeText(this, it, duration).show() } text?.let { Toast.makeText(this, it, duration).show() }
fun Context.getResourceUri(@AnyRes res: Int) = fun Context.getResourceUri(@AnyRes res: Int): Uri =
Uri.Builder() Uri.Builder()
.scheme(ContentResolver.SCHEME_ANDROID_RESOURCE) .scheme(ContentResolver.SCHEME_ANDROID_RESOURCE)
.authority(packageName) .authority(packageName)

@ -100,10 +100,8 @@ object FileHelper {
ContentResolver.SCHEME_CONTENT -> { ContentResolver.SCHEME_CONTENT -> {
val cursor = context.contentResolver.query(uri, null, null, null, null) val cursor = context.contentResolver.query(uri, null, null, null, null)
if (cursor != null && cursor.moveToFirst()) { if (cursor != null && cursor.moveToFirst()) {
return try { return cursor.use {
cursor.getString(cursor.getColumnIndexOrThrow(OpenableColumns.DISPLAY_NAME)) it.getString(it.getColumnIndexOrThrow(OpenableColumns.DISPLAY_NAME))
} finally {
cursor.close()
} }
} }
} }
@ -217,7 +215,7 @@ object FileHelper {
when (uri.scheme) { when (uri.scheme) {
ContentResolver.SCHEME_CONTENT -> { ContentResolver.SCHEME_CONTENT -> {
val dir = DocumentFile.fromTreeUri(context, uri) val dir = DocumentFile.fromTreeUri(context, uri)
val documentFiles = Arrays.asList(*dir!!.listFiles()) val documentFiles = listOf(*dir!!.listFiles())
while (true) { while (true) {
val result = tempName + extension val result = tempName + extension
if (Iterables.any(documentFiles) { f: DocumentFile? -> f!!.name == result }) { if (Iterables.any(documentFiles) { f: DocumentFile? -> f!!.name == result }) {

@ -259,8 +259,8 @@ class FilterCriteriaProvider @Inject constructor(
// EOD today if the specified date is NOW // EOD today if the specified date is NOW
or(Task.DUE_DATE.lte("?"), or(Task.DUE_DATE.lte("?"),
and(field("${Task.DUE_DATE} / 1000 % 60").eq(0), and(field("${Task.DUE_DATE} / 1000 % 60").eq(0),
field("?").eq(field("${PermaSql.VALUE_NOW}")), field("?").eq(field(PermaSql.VALUE_NOW)),
Task.DUE_DATE.lte("${PermaSql.VALUE_EOD}"))))) Task.DUE_DATE.lte(PermaSql.VALUE_EOD)))))
.toString(), .toString(),
values, values,
r.getStringArray(R.array.CFC_dueBefore_entries), r.getStringArray(R.array.CFC_dueBefore_entries),

@ -47,7 +47,10 @@ class CommentBarFragment : Fragment() {
lateinit var viewModel: TaskEditViewModel lateinit var viewModel: TaskEditViewModel
override fun onCreateView( override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View {
viewModel = ViewModelProvider(requireParentFragment())[TaskEditViewModel::class.java] viewModel = ViewModelProvider(requireParentFragment())[TaskEditViewModel::class.java]
val view = bind(container) val view = bind(container)
createView(savedInstanceState) createView(savedInstanceState)

@ -27,8 +27,7 @@ abstract class BaseInvoker(
withContext(Dispatchers.IO) { withContext(Dispatchers.IO) {
credentialsAdapter.checkToken() credentialsAdapter.checkToken()
Timber.d("%s request: %s", caller, request) Timber.d("%s request: %s", caller, request)
val response: T? val response: T? = try {
response = try {
if (preferences.isFlipperEnabled) { if (preferences.isFlipperEnabled) {
val start = DateUtilities.now() val start = DateUtilities.now()
val httpResponse = request.executeUnparsed() val httpResponse = request.executeUnparsed()

@ -22,12 +22,8 @@ abstract class BaseWorker(
} catch (e: Exception) { } catch (e: Exception) {
firebase.reportException(e) firebase.reportException(e)
Result.failure() Result.failure()
} finally {
destroy()
} }
} }
protected abstract suspend fun run(): Result protected abstract suspend fun run(): Result
protected open fun destroy() {}
} }

@ -47,7 +47,7 @@ import java.util.*
import java.util.concurrent.TimeUnit import java.util.concurrent.TimeUnit
import kotlin.math.max import kotlin.math.max
class WorkManagerImpl constructor( class WorkManagerImpl(
private val context: Context, private val context: Context,
private val preferences: Preferences, private val preferences: Preferences,
private val caldavDao: CaldavDao, private val caldavDao: CaldavDao,

@ -18,7 +18,6 @@ import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
import com.google.android.material.appbar.AppBarLayout import com.google.android.material.appbar.AppBarLayout
import com.google.android.material.appbar.AppBarLayout.Behavior.DragCallback import com.google.android.material.appbar.AppBarLayout.Behavior.DragCallback
import com.google.android.material.appbar.AppBarLayout.OnOffsetChangedListener
import com.google.android.material.appbar.CollapsingToolbarLayout import com.google.android.material.appbar.CollapsingToolbarLayout
import com.todoroo.andlib.utility.AndroidUtilities import com.todoroo.andlib.utility.AndroidUtilities
import dagger.hilt.android.AndroidEntryPoint import dagger.hilt.android.AndroidEntryPoint
@ -137,15 +136,14 @@ class LocationPickerActivity : InjectingAppCompatActivity(), Toolbar.OnMenuItemC
} }
}) })
params.behavior = behavior params.behavior = behavior
appBarLayout.addOnOffsetChangedListener( appBarLayout.addOnOffsetChangedListener { appBarLayout: AppBarLayout, offset: Int ->
OnOffsetChangedListener { appBarLayout: AppBarLayout, offset: Int -> if (offset == 0 && this.offset != 0) {
if (offset == 0 && this.offset != 0) { closeSearch()
closeSearch() AndroidUtilities.hideKeyboard(this)
AndroidUtilities.hideKeyboard(this) }
} this.offset = offset
this.offset = offset toolbar.alpha = abs(offset / appBarLayout.totalScrollRange.toFloat())
toolbar.alpha = abs(offset / appBarLayout.totalScrollRange.toFloat()) }
})
coordinatorLayout.addOnLayoutChangeListener( coordinatorLayout.addOnLayoutChangeListener(
object : View.OnLayoutChangeListener { object : View.OnLayoutChangeListener {
override fun onLayoutChange( override fun onLayoutChange(

@ -6,7 +6,7 @@ import timber.log.Timber
import java.util.concurrent.Executor import java.util.concurrent.Executor
import java.util.concurrent.Executors.newSingleThreadExecutor import java.util.concurrent.Executors.newSingleThreadExecutor
internal class Throttle constructor( internal class Throttle(
ratePerPeriod: Int, ratePerPeriod: Int,
private val periodMillis: Long = 1000, private val periodMillis: Long = 1000,
private val tag: String = "", private val tag: String = "",

@ -1,8 +1,11 @@
package org.tasks.preferences package org.tasks.preferences
import android.content.Context import android.content.Context
import com.todoroo.astrid.api.* import com.todoroo.astrid.api.CaldavFilter
import com.todoroo.astrid.api.CustomFilter
import com.todoroo.astrid.api.Filter import com.todoroo.astrid.api.Filter
import com.todoroo.astrid.api.GtasksFilter
import com.todoroo.astrid.api.TagFilter
import com.todoroo.astrid.core.BuiltInFilterExposer import com.todoroo.astrid.core.BuiltInFilterExposer
import com.todoroo.astrid.core.BuiltInFilterExposer.Companion.getMyTasksFilter import com.todoroo.astrid.core.BuiltInFilterExposer.Companion.getMyTasksFilter
import com.todoroo.astrid.data.Task import com.todoroo.astrid.data.Task
@ -10,8 +13,15 @@ import dagger.hilt.android.qualifiers.ApplicationContext
import kotlinx.coroutines.runBlocking import kotlinx.coroutines.runBlocking
import org.tasks.R import org.tasks.R
import org.tasks.Strings.isNullOrEmpty import org.tasks.Strings.isNullOrEmpty
import org.tasks.data.*
import org.tasks.data.CaldavCalendar.Companion.ACCESS_READ_ONLY import org.tasks.data.CaldavCalendar.Companion.ACCESS_READ_ONLY
import org.tasks.data.CaldavDao
import org.tasks.data.CaldavTask
import org.tasks.data.FilterDao
import org.tasks.data.GoogleTask
import org.tasks.data.GoogleTaskDao
import org.tasks.data.GoogleTaskListDao
import org.tasks.data.LocationDao
import org.tasks.data.TagDataDao
import org.tasks.filters.PlaceFilter import org.tasks.filters.PlaceFilter
import timber.log.Timber import timber.log.Timber
import javax.inject.Inject import javax.inject.Inject
@ -52,7 +62,7 @@ class DefaultFilterProvider @Inject constructor(
?.takeIf { it.isWritable } ?.takeIf { it.isWritable }
?: getAnyList() ?: getAnyList()
suspend fun getLastViewedFilter() = getFilterFromPreference(R.string.p_last_viewed_list) private suspend fun getLastViewedFilter() = getFilterFromPreference(R.string.p_last_viewed_list)
suspend fun getDefaultOpenFilter() = getFilterFromPreference(R.string.p_default_open_filter) suspend fun getDefaultOpenFilter() = getFilterFromPreference(R.string.p_default_open_filter)

@ -15,7 +15,7 @@ import org.tasks.time.DateTime
import org.tasks.ui.TimePreference import org.tasks.ui.TimePreference
import java.time.DayOfWeek import java.time.DayOfWeek
import java.time.format.TextStyle import java.time.format.TextStyle
import java.util.* import java.util.Locale
import javax.inject.Inject import javax.inject.Inject
private const val REQUEST_MORNING = 10007 private const val REQUEST_MORNING = 10007
@ -126,7 +126,7 @@ class DateAndTime : InjectingPreferenceFragment(), Preference.OnPreferenceChange
private fun updateStartOfWeek(value: String) { private fun updateStartOfWeek(value: String) {
val preference = getStartOfWeekPreference() val preference = getStartOfWeekPreference()
val index = preference.findIndexOfValue(value) val index = preference.findIndexOfValue(value)
val summary: String? = getWeekdayEntries().get(index) val summary: String? = getWeekdayEntries()[index]
preference.summary = summary preference.summary = summary
} }

@ -18,7 +18,7 @@ class TaskEditPreferences : InjectingPreferenceFragment() {
requireContext(), requireContext(),
R.drawable.ic_keyboard_arrow_right_24px R.drawable.ic_keyboard_arrow_right_24px
)?.mutate() )?.mutate()
tint = context?.getColor(R.color.icon_tint_with_alpha) tint = context.getColor(R.color.icon_tint_with_alpha)
iconVisible = true iconVisible = true
} }
} }

@ -1,6 +1,10 @@
package org.tasks.preferences.fragments package org.tasks.preferences.fragments
import android.content.* import android.content.BroadcastReceiver
import android.content.ClipData
import android.content.ClipboardManager
import android.content.Context
import android.content.Intent
import android.os.Bundle import android.os.Bundle
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View import android.view.View
@ -33,7 +37,7 @@ import org.tasks.jobs.WorkManager
import org.tasks.preferences.IconPreference import org.tasks.preferences.IconPreference
import org.tasks.preferences.fragments.MainSettingsFragment.Companion.REQUEST_TASKS_ORG import org.tasks.preferences.fragments.MainSettingsFragment.Companion.REQUEST_TASKS_ORG
import java.time.format.FormatStyle import java.time.format.FormatStyle
import java.util.* import java.util.Locale
import javax.inject.Inject import javax.inject.Inject
@AndroidEntryPoint @AndroidEntryPoint
@ -171,7 +175,7 @@ class TasksAccount : BaseAccountPreference() {
onPreferenceClickListener = null onPreferenceClickListener = null
} else { } else {
setOnPreferenceClickListener { setOnPreferenceClickListener {
context?.openUri(R.string.url_sponsor) context.openUri(R.string.url_sponsor)
false false
} }
} }
@ -231,7 +235,7 @@ class TasksAccount : BaseAccountPreference() {
category.addPreference(IconPreference(requireContext()).apply { category.addPreference(IconPreference(requireContext()).apply {
layoutResource = R.layout.preference_icon layoutResource = R.layout.preference_icon
iconVisible = true iconVisible = true
drawable = context?.getDrawable(R.drawable.ic_outline_delete_24px) drawable = context.getDrawable(R.drawable.ic_outline_delete_24px)
tint = ContextCompat.getColor(requireContext(), R.color.icon_tint_with_alpha) tint = ContextCompat.getColor(requireContext(), R.color.icon_tint_with_alpha)
title = description title = description
iconClickListener = View.OnClickListener { _ -> iconClickListener = View.OnClickListener { _ ->

@ -5,11 +5,11 @@ import android.content.res.Resources
import com.todoroo.andlib.utility.DateUtilities import com.todoroo.andlib.utility.DateUtilities
import org.tasks.R import org.tasks.R
import org.tasks.data.Alarm import org.tasks.data.Alarm
import java.util.* import java.util.Locale
import java.util.concurrent.TimeUnit import java.util.concurrent.TimeUnit
import kotlin.math.absoluteValue import kotlin.math.absoluteValue
class AlarmToString constructor(context: Context, var locale: Locale) { class AlarmToString(context: Context, var locale: Locale) {
private val resources = context.resources private val resources = context.resources
fun toString(alarm: Alarm): String { fun toString(alarm: Alarm): String {

@ -52,7 +52,7 @@ class BasicRecurrenceDialog : DialogFragment() {
val adapter = SingleCheckedArrayAdapter(requireContext(), repeatOptions) val adapter = SingleCheckedArrayAdapter(requireContext(), repeatOptions)
var selected = 0 var selected = 0
if (customPicked) { if (customPicked) {
adapter.insert(repeatRuleToString!!.toString(rule), 0) adapter.insert(repeatRuleToString.toString(rule), 0)
} else if (rrule != null) { } else if (rrule != null) {
selected = when (rrule.frequency) { selected = when (rrule.frequency) {
Recur.Frequency.DAILY -> 1 Recur.Frequency.DAILY -> 1

@ -3,7 +3,7 @@ package org.tasks.sync
import kotlinx.coroutines.delay import kotlinx.coroutines.delay
import timber.log.Timber import timber.log.Timber
class Debouncer constructor(private val tag: String, private val block: suspend (Boolean) -> Unit) { class Debouncer(private val tag: String, private val block: suspend (Boolean) -> Unit) {
private var count = 0 private var count = 0
suspend fun sync(immediate: Boolean) { suspend fun sync(immediate: Boolean) {

@ -31,7 +31,7 @@ class HeaderFormatter @Inject constructor(
headerString(value, groupMode, alwaysDisplayFullDate, style, compact) headerString(value, groupMode, alwaysDisplayFullDate, style, compact)
} }
suspend fun headerString( private suspend fun headerString(
value: Long, value: Long,
groupMode: Int = preferences.groupMode, groupMode: Int = preferences.groupMode,
alwaysDisplayFullDate: Boolean = preferences.alwaysDisplayFullDate, alwaysDisplayFullDate: Boolean = preferences.alwaysDisplayFullDate,

@ -7,7 +7,7 @@ import com.todoroo.astrid.core.SortHelper
import org.tasks.data.TaskContainer import org.tasks.data.TaskContainer
import org.tasks.time.DateTimeUtils.startOfDay import org.tasks.time.DateTimeUtils.startOfDay
class SectionedDataSource constructor( class SectionedDataSource(
tasks: List<TaskContainer>, tasks: List<TaskContainer>,
disableHeaders: Boolean, disableHeaders: Boolean,
val groupMode: Int, val groupMode: Int,
@ -144,7 +144,7 @@ class SectionedDataSource constructor(
sections.remove(toPosition) sections.remove(toPosition)
val newSectionedPosition = old.sectionedPosition + offset val newSectionedPosition = old.sectionedPosition + offset
val previousSection = if (isHeader(newSectionedPosition - 1)) sections[newSectionedPosition - 1] else null val previousSection = if (isHeader(newSectionedPosition - 1)) sections[newSectionedPosition - 1] else null
val newFirstPosition = previousSection?.firstPosition ?: old.firstPosition + offset val newFirstPosition = previousSection?.firstPosition ?: (old.firstPosition + offset)
val new = AdapterSection(newFirstPosition, old.value, newSectionedPosition, old.collapsed) val new = AdapterSection(newFirstPosition, old.value, newSectionedPosition, old.collapsed)
sections.append(new.sectionedPosition, new) sections.append(new.sectionedPosition, new)
} }

@ -40,7 +40,7 @@ class SubtaskControlSet : TaskEditControlFragment() {
@Inject lateinit var colorProvider: ColorProvider @Inject lateinit var colorProvider: ColorProvider
@Inject lateinit var preferences: Preferences @Inject lateinit var preferences: Preferences
lateinit var listViewModel: TaskListViewModel private lateinit var listViewModel: TaskListViewModel
override fun createView(savedInstanceState: Bundle?) { override fun createView(savedInstanceState: Bundle?) {
viewModel.task.takeIf { it.id > 0 }?.let { viewModel.task.takeIf { it.id > 0 }?.let {

@ -1,6 +1,6 @@
<vector android:height="36dp" android:viewportHeight="1024" <vector android:height="36dp" android:viewportHeight="1024"
android:viewportWidth="1024" android:width="36dp" android:viewportWidth="1024" android:width="36dp"
xmlns:aapt="http://schemas.android.com/aapt" xmlns:android="http://schemas.android.com/apk/res/android"> xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="#77A646" android:pathData="M887.67,957.05L140.08,957.05c-39.35,0 -71.25,-31.9 -71.25,-71.25L68.82,138.2c0,-39.35 31.9,-71.25 71.25,-71.25l747.6,0c39.35,0 71.25,31.9 71.25,71.25l0,747.6c0,39.35 -31.9,71.25 -71.25,71.25z"/> <path android:fillColor="#77A646" android:pathData="M887.67,957.05L140.08,957.05c-39.35,0 -71.25,-31.9 -71.25,-71.25L68.82,138.2c0,-39.35 31.9,-71.25 71.25,-71.25l747.6,0c39.35,0 71.25,31.9 71.25,71.25l0,747.6c0,39.35 -31.9,71.25 -71.25,71.25z"/>
<path android:fillColor="#A2CF6E" android:pathData="M887.67,918.68L140.08,918.68c-39.35,0 -71.25,-31.9 -71.25,-71.25L68.82,138.2c0,-39.35 31.9,-71.25 71.25,-71.25l747.6,0c39.35,0 71.25,31.9 71.25,71.25l0,709.23c0,39.35 -31.9,71.25 -71.25,71.25z"/> <path android:fillColor="#A2CF6E" android:pathData="M887.67,918.68L140.08,918.68c-39.35,0 -71.25,-31.9 -71.25,-71.25L68.82,138.2c0,-39.35 31.9,-71.25 71.25,-71.25l747.6,0c39.35,0 71.25,31.9 71.25,71.25l0,709.23c0,39.35 -31.9,71.25 -71.25,71.25z"/>
<path android:fillColor="#8BC34A" android:pathData="M887.67,935.13L140.08,935.13c-39.35,0 -71.25,-31.9 -71.25,-71.25L68.82,160.12c0,-39.35 31.9,-71.25 71.25,-71.25l747.6,0c39.35,0 71.25,31.9 71.25,71.25l0,703.75c0,39.35 -31.9,71.25 -71.25,71.25z"/> <path android:fillColor="#8BC34A" android:pathData="M887.67,935.13L140.08,935.13c-39.35,0 -71.25,-31.9 -71.25,-71.25L68.82,160.12c0,-39.35 31.9,-71.25 71.25,-71.25l747.6,0c39.35,0 71.25,31.9 71.25,71.25l0,703.75c0,39.35 -31.9,71.25 -71.25,71.25z"/>

@ -1,7 +1,5 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" <LinearLayout 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/root_layout" android:id="@+id/root_layout"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"

@ -1,9 +1,7 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content">
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto">
<ScrollView <ScrollView
android:id="@+id/scrollView2" android:id="@+id/scrollView2"

@ -1,6 +1,5 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" <LinearLayout 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_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
xmlns:tools="http://schemas.android.com/tools" xmlns:tools="http://schemas.android.com/tools"

@ -1,7 +1,6 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools" xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/widget_row" android:id="@+id/widget_row"
android:background="@drawable/widget_ripple_dark" android:background="@drawable/widget_ripple_dark"
android:layout_width="match_parent" android:layout_width="match_parent"

@ -108,7 +108,7 @@
<string name="custom_filter_and">かつ</string> <string name="custom_filter_and">かつ</string>
<string name="CFA_button_add">条件を追加</string> <string name="CFA_button_add">条件を追加</string>
<string name="CFC_dueBefore_text">締切: \?</string> <string name="CFC_dueBefore_text">締切: \?</string>
<string name="CFC_dueBefore_name">...に締切</string> <string name="CFC_dueBefore_name">に締切</string>
<string name="no_due_date">締切日時なし</string> <string name="no_due_date">締切日時なし</string>
<string name="next_month">1 か月後</string> <string name="next_month">1 か月後</string>
<string name="CFC_importance_text">優先度</string> <string name="CFC_importance_text">優先度</string>
@ -497,7 +497,7 @@
<string name="ok">OK</string> <string name="ok">OK</string>
<string name="always_display_full_date">完全な日付を表示</string> <string name="always_display_full_date">完全な日付を表示</string>
<string name="astrid_sort_order_summary">「マイタスク」「今日」そしてタグにおいて Astrid の手動並べ替えモードを有効にします。この並べ替えモードは将来のアップデートで「マイ設定」に置き換えられる予定です</string> <string name="astrid_sort_order_summary">「マイタスク」「今日」そしてタグにおいて Astrid の手動並べ替えモードを有効にします。この並べ替えモードは将来のアップデートで「マイ設定」に置き換えられる予定です</string>
<string name="CFC_startBefore_name">...に着手</string> <string name="CFC_startBefore_name">に着手</string>
<string name="widget_due_date_reschedule">タスクを再計画</string> <string name="widget_due_date_reschedule">タスクを再計画</string>
<plurals name="reminder_minutes"> <plurals name="reminder_minutes">
<item quantity="other"></item> <item quantity="other"></item>

@ -16,7 +16,6 @@
<string name="TAd_actionEditTask">ပြုပြင်</string> <string name="TAd_actionEditTask">ပြုပြင်</string>
<string name="manage_drawer">မီနူး ကိုပြင်ဆင်မည်</string> <string name="manage_drawer">မီနူး ကိုပြင်ဆင်မည်</string>
<string name="SSD_sort_my_order">အစီအစဥ်</string> <string name="SSD_sort_my_order">အစီအစဥ်</string>
<string name="astrid_sort_order"></string>
<string name="SSD_sort_importance">အရေးပါမှုအားဖြင့်</string> <string name="SSD_sort_importance">အရေးပါမှုအားဖြင့်</string>
<string name="sort_list">စာရင်းဖြင့်</string> <string name="sort_list">စာရင်းဖြင့်</string>
<string name="sort_completed">အလုပ်ပြီးသောအချိန်ဖြင့်</string> <string name="sort_completed">အလုပ်ပြီးသောအချိန်ဖြင့်</string>

@ -8,9 +8,3 @@
# project structure. # project structure.
# Indicates whether an apk should be generated for each density. # Indicates whether an apk should be generated for each density.
split.density=false
# Project target.
target=android-19
apk-configurations=
android.library.reference.1=../api

Loading…
Cancel
Save