1 /*
2  * Copyright (C) 2020 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.deskclock.data
18 
19 import android.content.Context
20 import android.text.format.DateUtils.HOUR_IN_MILLIS
21 import android.text.format.DateUtils.MINUTE_IN_MILLIS
22 import android.text.format.DateUtils.SECOND_IN_MILLIS
23 import androidx.annotation.StringRes
24 
25 import com.android.deskclock.R
26 import com.android.deskclock.Utils
27 
28 object TimerStringFormatter {
29     /**
30      * Format "7 hours 52 minutes 14 seconds remaining"
31      */
32     @JvmStatic
formatTimeRemainingnull33     fun formatTimeRemaining(
34         context: Context,
35         remainingTime: Long,
36         shouldShowSeconds: Boolean
37     ): String? {
38         var roundedHours = (remainingTime / HOUR_IN_MILLIS).toInt()
39         var roundedMinutes = (remainingTime / MINUTE_IN_MILLIS % 60).toInt()
40         var roundedSeconds = (remainingTime / SECOND_IN_MILLIS % 60).toInt()
41 
42         val seconds: Int
43         val minutes: Int
44         val hours: Int
45         if (remainingTime % SECOND_IN_MILLIS != 0L && shouldShowSeconds) {
46             // Add 1 because there's a partial second.
47             roundedSeconds += 1
48             if (roundedSeconds == 60) {
49                 // Wind back and fix the hours and minutes as needed.
50                 seconds = 0
51                 roundedMinutes += 1
52                 if (roundedMinutes == 60) {
53                     minutes = 0
54                     roundedHours += 1
55                     hours = roundedHours
56                 } else {
57                     minutes = roundedMinutes
58                     hours = roundedHours
59                 }
60             } else {
61                 seconds = roundedSeconds
62                 minutes = roundedMinutes
63                 hours = roundedHours
64             }
65         } else {
66             // Already perfect precision, or we don't want to consider seconds at all.
67             seconds = roundedSeconds
68             minutes = roundedMinutes
69             hours = roundedHours
70         }
71 
72         val minSeq = Utils.getNumberFormattedQuantityString(context, R.plurals.minutes, minutes)
73         val hourSeq = Utils.getNumberFormattedQuantityString(context, R.plurals.hours, hours)
74         val secSeq = Utils.getNumberFormattedQuantityString(context, R.plurals.seconds, seconds)
75 
76         // The verb "remaining" may have to change tense for singular subjects in some languages.
77         val remainingSuffix: String =
78                 context.getString(if (minutes > 1 || hours > 1 || seconds > 1) {
79                     R.string.timer_remaining_multiple
80                 } else {
81                     R.string.timer_remaining_single
82                 })
83 
84         val showHours = hours > 0
85         val showMinutes = minutes > 0
86         val showSeconds = seconds > 0 && shouldShowSeconds
87 
88         var formatStringId = -1
89         if (showHours) {
90             formatStringId = if (showMinutes) {
91                 if (showSeconds) {
92                     R.string.timer_notifications_hours_minutes_seconds
93                 } else {
94                     R.string.timer_notifications_hours_minutes
95                 }
96             } else if (showSeconds) {
97                 R.string.timer_notifications_hours_seconds
98             } else {
99                 R.string.timer_notifications_hours
100             }
101         } else if (showMinutes) {
102             formatStringId = if (showSeconds) {
103                 R.string.timer_notifications_minutes_seconds
104             } else {
105                 R.string.timer_notifications_minutes
106             }
107         } else if (showSeconds) {
108             formatStringId = R.string.timer_notifications_seconds
109         } else if (!shouldShowSeconds) {
110             formatStringId = R.string.timer_notifications_less_min
111         }
112 
113         return if (formatStringId == -1) {
114             null
115         } else {
116             String.format(context.getString(formatStringId), hourSeq, minSeq,
117                     remainingSuffix, secSeq)
118         }
119     }
120 
121     @JvmStatic
formatStringnull122     fun formatString(
123         context: Context,
124         @StringRes stringResId: Int,
125         currentTime: Long,
126         shouldShowSeconds: Boolean
127     ): String {
128         return String.format(context.getString(stringResId),
129                 formatTimeRemaining(context, currentTime, shouldShowSeconds))
130     }
131 }