Skip to content

Commit

Permalink
Date and time picker in Change time
Browse files Browse the repository at this point in the history
  • Loading branch information
BinTianqi committed Dec 8, 2024
1 parent 380675c commit f7b18d1
Show file tree
Hide file tree
Showing 6 changed files with 143 additions and 17 deletions.
10 changes: 10 additions & 0 deletions app/src/main/java/com/bintianqi/owndroid/Utils.kt
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,12 @@ import java.io.File
import java.io.FileNotFoundException
import java.io.IOException
import java.io.InputStream
import java.text.SimpleDateFormat
import java.time.Instant
import java.time.ZoneId
import java.time.format.DateTimeFormatter
import java.time.format.FormatStyle
import java.util.Date
import java.util.Locale

lateinit var getFile: ActivityResultLauncher<Intent>
Expand Down Expand Up @@ -132,3 +135,10 @@ fun parseTimestamp(timestamp: Long): String {
val formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss").withZone(ZoneId.systemDefault())
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))

124 changes: 111 additions & 13 deletions app/src/main/java/com/bintianqi/owndroid/dpm/System.kt
Original file line number Diff line number Diff line change
Expand Up @@ -45,15 +45,20 @@ import android.widget.Toast
import androidx.compose.animation.AnimatedVisibility
import androidx.compose.animation.animateContentSize
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.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.lazy.LazyColumn
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.text.KeyboardActions
import androidx.compose.foundation.text.KeyboardOptions
Expand All @@ -63,14 +68,23 @@ import androidx.compose.material.icons.filled.Add
import androidx.compose.material3.AlertDialog
import androidx.compose.material3.Button
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.IconButton
import androidx.compose.material3.MaterialTheme.colorScheme
import androidx.compose.material3.MaterialTheme.typography
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.Text
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.LaunchedEffect
import androidx.compose.runtime.collectAsState
Expand Down Expand Up @@ -102,6 +116,7 @@ import com.bintianqi.owndroid.exportFilePath
import com.bintianqi.owndroid.fileUriFlow
import com.bintianqi.owndroid.formatFileSize
import com.bintianqi.owndroid.getFile
import com.bintianqi.owndroid.humanReadableDate
import com.bintianqi.owndroid.prepareForNotification
import com.bintianqi.owndroid.selectedPackage
import com.bintianqi.owndroid.toggle
Expand Down Expand Up @@ -360,33 +375,116 @@ fun Keyguard(navCtrl: NavHostController) {
}
}

@OptIn(ExperimentalMaterial3Api::class)
@SuppressLint("NewApi")
@Composable
fun ChangeTime(navCtrl: NavHostController) {
val context = LocalContext.current
val dpm = context.getDPM()
val receiver = context.getReceiver()
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) {
OutlinedTextField(
value = inputTime,
label = { Text(stringResource(R.string.time_unit_ms)) },
onValueChange = { inputTime = it },
supportingText = { Text(stringResource(R.string.info_change_time)) },
keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Number, imeAction = ImeAction.Done),
keyboardActions = KeyboardActions(onDone = {focusMgr.clearFocus() }),
modifier = Modifier.fillMaxWidth()
)
Spacer(Modifier.padding(vertical = 5.dp))
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(
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,
label = { Text(stringResource(R.string.time_unit_ms)) },
onValueChange = { inputTime = it },
supportingText = { Text(stringResource(R.string.info_change_time)) },
keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Number, imeAction = ImeAction.Done),
keyboardActions = KeyboardActions(onDone = {focusMgr.clearFocus() }),
modifier = Modifier.fillMaxWidth()
)
}
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(),
enabled = inputTime != ""
enabled = isInputLegal
) {
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")
Expand Down
9 changes: 7 additions & 2 deletions app/src/main/res/values-ru/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -143,8 +143,13 @@
<string name="bug_report">Отчет об ошибке</string>
<string name="confirm_bug_report">Запросить отчет об ошибке?</string>
<string name="reboot">Перезагрузить</string>
<string name="change_time">Change time</string> <!--TODO-->
<string name="change_timezone">Change timezone</string> <!--TODO-->
<!--TODO: the following 6 strings-->
<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="disable_auto_time_zone_before_set">Автоматический часовой пояс должен быть отключен перед установкой пользовательского часового пояса.</string>
<string name="permission_policy">Политика разрешений</string>
Expand Down
9 changes: 7 additions & 2 deletions app/src/main/res/values-tr/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -144,8 +144,13 @@
<string name="bug_report">Hata raporu</string>
<string name="confirm_bug_report">Hata raporu iste?</string>
<string name="reboot">Yeniden başlat</string>
<string name="change_time">Change time</string> <!--TODO-->
<string name="change_timezone">Change timezone</string><!--TODO-->
<!--TODO: the following 6 strings-->
<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="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>
Expand Down
4 changes: 4 additions & 0 deletions app/src/main/res/values-zh-rCN/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,10 @@
<string name="confirm_bug_report">请求错误报告?</string>
<string name="reboot">重启</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="timezone_id">时区ID</string>
<string name="disable_auto_time_zone_before_set">在设置时区前需要关闭自动时区</string>
Expand Down
4 changes: 4 additions & 0 deletions app/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,10 @@
<string name="confirm_bug_report">Request bug report?</string>
<string name="reboot">Reboot</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="timezone_id">Timezone ID</string>
<string name="disable_auto_time_zone_before_set">Auto timezone should be disabled before set a custom timezone. </string>
Expand Down

0 comments on commit f7b18d1

Please sign in to comment.