Date and time picker in Change time

This commit is contained in:
BinTianqi
2024-12-08 14:19:11 +08:00
parent 380675cf8f
commit f7b18d1a31
6 changed files with 143 additions and 17 deletions

View File

@@ -23,9 +23,12 @@ import java.io.File
import java.io.FileNotFoundException import java.io.FileNotFoundException
import java.io.IOException import java.io.IOException
import java.io.InputStream import java.io.InputStream
import java.text.SimpleDateFormat
import java.time.Instant import java.time.Instant
import java.time.ZoneId import java.time.ZoneId
import java.time.format.DateTimeFormatter import java.time.format.DateTimeFormatter
import java.time.format.FormatStyle
import java.util.Date
import java.util.Locale import java.util.Locale
lateinit var getFile: ActivityResultLauncher<Intent> lateinit var getFile: ActivityResultLauncher<Intent>
@@ -132,3 +135,10 @@ fun parseTimestamp(timestamp: Long): String {
val formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss").withZone(ZoneId.systemDefault()) val formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss").withZone(ZoneId.systemDefault())
return formatter.format(instant) return formatter.format(instant)
} }
val Long.humanReadableDate: String
get() = SimpleDateFormat("yyyy/MM/dd", Locale.getDefault()).format(Date(this))
val Long.humanReadableTime: String
get() = SimpleDateFormat("HH:mm:ss", Locale.getDefault()).format(Date(this))

View File

@@ -45,15 +45,20 @@ import android.widget.Toast
import androidx.compose.animation.AnimatedVisibility import androidx.compose.animation.AnimatedVisibility
import androidx.compose.animation.animateContentSize import androidx.compose.animation.animateContentSize
import androidx.compose.foundation.clickable import androidx.compose.foundation.clickable
import androidx.compose.foundation.interaction.MutableInteractionSource
import androidx.compose.foundation.interaction.collectIsPressedAsState
import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.width import androidx.compose.foundation.layout.width
import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items import androidx.compose.foundation.lazy.items
import androidx.compose.foundation.pager.HorizontalPager
import androidx.compose.foundation.pager.rememberPagerState
import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.foundation.text.KeyboardActions import androidx.compose.foundation.text.KeyboardActions
import androidx.compose.foundation.text.KeyboardOptions import androidx.compose.foundation.text.KeyboardOptions
@@ -63,14 +68,23 @@ import androidx.compose.material.icons.filled.Add
import androidx.compose.material3.AlertDialog import androidx.compose.material3.AlertDialog
import androidx.compose.material3.Button import androidx.compose.material3.Button
import androidx.compose.material3.ButtonDefaults import androidx.compose.material3.ButtonDefaults
import androidx.compose.material3.DatePicker
import androidx.compose.material3.DatePickerDialog
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.Icon import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton import androidx.compose.material3.IconButton
import androidx.compose.material3.MaterialTheme.colorScheme import androidx.compose.material3.MaterialTheme.colorScheme
import androidx.compose.material3.MaterialTheme.typography import androidx.compose.material3.MaterialTheme.typography
import androidx.compose.material3.OutlinedTextField import androidx.compose.material3.OutlinedTextField
import androidx.compose.material3.SegmentedButton
import androidx.compose.material3.SegmentedButtonDefaults
import androidx.compose.material3.SingleChoiceSegmentedButtonRow
import androidx.compose.material3.Switch import androidx.compose.material3.Switch
import androidx.compose.material3.Text import androidx.compose.material3.Text
import androidx.compose.material3.TextButton import androidx.compose.material3.TextButton
import androidx.compose.material3.TimePicker
import androidx.compose.material3.rememberDatePickerState
import androidx.compose.material3.rememberTimePickerState
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.collectAsState import androidx.compose.runtime.collectAsState
@@ -102,6 +116,7 @@ import com.bintianqi.owndroid.exportFilePath
import com.bintianqi.owndroid.fileUriFlow import com.bintianqi.owndroid.fileUriFlow
import com.bintianqi.owndroid.formatFileSize import com.bintianqi.owndroid.formatFileSize
import com.bintianqi.owndroid.getFile import com.bintianqi.owndroid.getFile
import com.bintianqi.owndroid.humanReadableDate
import com.bintianqi.owndroid.prepareForNotification import com.bintianqi.owndroid.prepareForNotification
import com.bintianqi.owndroid.selectedPackage import com.bintianqi.owndroid.selectedPackage
import com.bintianqi.owndroid.toggle import com.bintianqi.owndroid.toggle
@@ -360,6 +375,7 @@ fun Keyguard(navCtrl: NavHostController) {
} }
} }
@OptIn(ExperimentalMaterial3Api::class)
@SuppressLint("NewApi") @SuppressLint("NewApi")
@Composable @Composable
fun ChangeTime(navCtrl: NavHostController) { fun ChangeTime(navCtrl: NavHostController) {
@@ -367,9 +383,67 @@ fun ChangeTime(navCtrl: NavHostController) {
val dpm = context.getDPM() val dpm = context.getDPM()
val receiver = context.getReceiver() val receiver = context.getReceiver()
val focusMgr = LocalFocusManager.current val focusMgr = LocalFocusManager.current
var inputTime by remember { mutableStateOf("") } val coroutine = rememberCoroutineScope()
val pagerState = rememberPagerState { 2 }
var manualInput by remember { mutableStateOf(false) }
var inputTime by remember { mutableStateOf("")}
var picker by remember { mutableIntStateOf(0) } //0:None, 1:DatePicker, 2:TimePicker
val datePickerState = rememberDatePickerState()
val timePickerState = rememberTimePickerState()
val dateInteractionSource = remember { MutableInteractionSource() }
val timeInteractionSource = remember { MutableInteractionSource() }
if(dateInteractionSource.collectIsPressedAsState().value) picker = 1
if(timeInteractionSource.collectIsPressedAsState().value) picker = 2
val isInputLegal = (manualInput && (try { inputTime.toLong() } catch(_: Exception) { -1 }) >= 0) ||
(!manualInput && datePickerState.selectedDateMillis != null)
MyScaffold(R.string.change_time, 8.dp, navCtrl) { MyScaffold(R.string.change_time, 8.dp, navCtrl) {
SingleChoiceSegmentedButtonRow(
modifier = Modifier.fillMaxWidth().padding(top = 4.dp)
) {
SegmentedButton(
selected = !manualInput, shape = SegmentedButtonDefaults.itemShape(0, 2),
onClick = {
manualInput = false
coroutine.launch {
pagerState.animateScrollToPage(0)
}
}
) {
Text(stringResource(R.string.selector))
}
SegmentedButton(
selected = manualInput, shape = SegmentedButtonDefaults.itemShape(1, 2),
onClick = {
manualInput = true
coroutine.launch {
pagerState.animateScrollToPage(1)
}
}
) {
Text(stringResource(R.string.manually_input))
}
}
HorizontalPager(
state = pagerState, modifier = Modifier.height(140.dp).padding(top = 4.dp),
verticalAlignment = Alignment.Top
) { page ->
if(page == 0) Column {
OutlinedTextField( OutlinedTextField(
value = datePickerState.selectedDateMillis?.humanReadableDate ?: "",
onValueChange = {}, readOnly = true,
label = { Text(stringResource(R.string.date)) },
interactionSource = dateInteractionSource,
modifier = Modifier.fillMaxWidth()
)
OutlinedTextField(
value = timePickerState.hour.toString() + ":" + timePickerState.minute.toString(),
onValueChange = {}, readOnly = true,
label = { Text(stringResource(R.string.time)) },
interactionSource = timeInteractionSource,
modifier = Modifier.fillMaxWidth()
)
}
if(page == 1) OutlinedTextField(
value = inputTime, value = inputTime,
label = { Text(stringResource(R.string.time_unit_ms)) }, label = { Text(stringResource(R.string.time_unit_ms)) },
onValueChange = { inputTime = it }, onValueChange = { inputTime = it },
@@ -378,15 +452,39 @@ fun ChangeTime(navCtrl: NavHostController) {
keyboardActions = KeyboardActions(onDone = {focusMgr.clearFocus() }), keyboardActions = KeyboardActions(onDone = {focusMgr.clearFocus() }),
modifier = Modifier.fillMaxWidth() modifier = Modifier.fillMaxWidth()
) )
Spacer(Modifier.padding(vertical = 5.dp)) }
Button( Button(
onClick = { dpm.setTime(receiver, inputTime.toLong()) }, onClick = {
val timeMillis = if(manualInput) inputTime.toLong()
else datePickerState.selectedDateMillis!! + timePickerState.hour * 3600000 + timePickerState.minute * 60000
val result = dpm.setTime(receiver, timeMillis)
Toast.makeText(context, if(result) R.string.success else R.string.failed, Toast.LENGTH_SHORT).show()
},
modifier = Modifier.fillMaxWidth(), modifier = Modifier.fillMaxWidth(),
enabled = inputTime != "" enabled = isInputLegal
) { ) {
Text(stringResource(R.string.apply)) Text(stringResource(R.string.apply))
} }
} }
if(picker == 1) DatePickerDialog(
confirmButton = {
TextButton(onClick = { picker = 0; focusMgr.clearFocus() } ) {
Text(stringResource(R.string.confirm))
}
},
onDismissRequest = { picker = 0; focusMgr.clearFocus() }
) {
DatePicker(datePickerState)
}
if(picker == 2) AlertDialog(
text = { TimePicker(timePickerState) },
confirmButton = {
TextButton(onClick = { picker = 0; focusMgr.clearFocus() } ) {
Text(stringResource(R.string.confirm))
}
},
onDismissRequest = { picker = 0; focusMgr.clearFocus() }
)
} }
@SuppressLint("NewApi") @SuppressLint("NewApi")

View File

@@ -143,8 +143,13 @@
<string name="bug_report">Отчет об ошибке</string> <string name="bug_report">Отчет об ошибке</string>
<string name="confirm_bug_report">Запросить отчет об ошибке?</string> <string name="confirm_bug_report">Запросить отчет об ошибке?</string>
<string name="reboot">Перезагрузить</string> <string name="reboot">Перезагрузить</string>
<string name="change_time">Change time</string> <!--TODO--> <!--TODO: the following 6 strings-->
<string name="change_timezone">Change timezone</string> <!--TODO--> <string name="change_time">Change time</string>
<string name="selector">Selector</string>
<string name="manually_input">Manually input</string>
<string name="date">Date</string>
<string name="time">Time</string>
<string name="change_timezone">Change timezone</string>
<string name="timezone_id">Идентификатор часового пояса</string> <string name="timezone_id">Идентификатор часового пояса</string>
<string name="disable_auto_time_zone_before_set">Автоматический часовой пояс должен быть отключен перед установкой пользовательского часового пояса.</string> <string name="disable_auto_time_zone_before_set">Автоматический часовой пояс должен быть отключен перед установкой пользовательского часового пояса.</string>
<string name="permission_policy">Политика разрешений</string> <string name="permission_policy">Политика разрешений</string>

View File

@@ -144,8 +144,13 @@
<string name="bug_report">Hata raporu</string> <string name="bug_report">Hata raporu</string>
<string name="confirm_bug_report">Hata raporu iste?</string> <string name="confirm_bug_report">Hata raporu iste?</string>
<string name="reboot">Yeniden başlat</string> <string name="reboot">Yeniden başlat</string>
<string name="change_time">Change time</string> <!--TODO--> <!--TODO: the following 6 strings-->
<string name="change_timezone">Change timezone</string><!--TODO--> <string name="change_time">Change time</string>
<string name="selector">Selector</string>
<string name="manually_input">Manually input</string>
<string name="date">Date</string>
<string name="time">Time</string>
<string name="change_timezone">Change timezone</string>
<string name="timezone_id">Saat dilimi kimliği</string> <string name="timezone_id">Saat dilimi kimliği</string>
<string name="disable_auto_time_zone_before_set">Özel bir saat dilimi ayarlamadan önce otomatik saat dilimi devre dışı bırakılmalıdır</string> <string name="disable_auto_time_zone_before_set">Özel bir saat dilimi ayarlamadan önce otomatik saat dilimi devre dışı bırakılmalıdır</string>
<string name="permission_policy">İzin politikası</string> <string name="permission_policy">İzin politikası</string>

View File

@@ -140,6 +140,10 @@
<string name="confirm_bug_report">请求错误报告?</string> <string name="confirm_bug_report">请求错误报告?</string>
<string name="reboot">重启</string> <string name="reboot">重启</string>
<string name="change_time">更改时间</string> <string name="change_time">更改时间</string>
<string name="selector">选择器</string>
<string name="manually_input">手动输入</string>
<string name="date">日期</string>
<string name="time">时间</string>
<string name="change_timezone">更改时区</string> <string name="change_timezone">更改时区</string>
<string name="timezone_id">时区ID</string> <string name="timezone_id">时区ID</string>
<string name="disable_auto_time_zone_before_set">在设置时区前需要关闭自动时区</string> <string name="disable_auto_time_zone_before_set">在设置时区前需要关闭自动时区</string>

View File

@@ -150,6 +150,10 @@
<string name="confirm_bug_report">Request bug report?</string> <string name="confirm_bug_report">Request bug report?</string>
<string name="reboot">Reboot</string> <string name="reboot">Reboot</string>
<string name="change_time">Change time</string> <string name="change_time">Change time</string>
<string name="selector">Selector</string>
<string name="manually_input">Manually input</string>
<string name="date">Date</string>
<string name="time">Time</string>
<string name="change_timezone">Change timezone</string> <string name="change_timezone">Change timezone</string>
<string name="timezone_id">Timezone ID</string> <string name="timezone_id">Timezone ID</string>
<string name="disable_auto_time_zone_before_set">Auto timezone should be disabled before set a custom timezone. </string> <string name="disable_auto_time_zone_before_set">Auto timezone should be disabled before set a custom timezone. </string>