├── app
├── .gitignore
├── src
│ └── main
│ │ ├── ic_launcher-playstore.png
│ │ ├── res
│ │ ├── mipmap-hdpi
│ │ │ ├── ic_launcher.webp
│ │ │ ├── ic_launcher_round.webp
│ │ │ └── ic_launcher_foreground.webp
│ │ ├── mipmap-mdpi
│ │ │ ├── ic_launcher.webp
│ │ │ ├── ic_launcher_round.webp
│ │ │ └── ic_launcher_foreground.webp
│ │ ├── mipmap-xhdpi
│ │ │ ├── ic_launcher.webp
│ │ │ ├── ic_launcher_round.webp
│ │ │ └── ic_launcher_foreground.webp
│ │ ├── mipmap-xxhdpi
│ │ │ ├── ic_launcher.webp
│ │ │ ├── ic_launcher_round.webp
│ │ │ └── ic_launcher_foreground.webp
│ │ ├── mipmap-xxxhdpi
│ │ │ ├── ic_launcher.webp
│ │ │ ├── ic_launcher_round.webp
│ │ │ └── ic_launcher_foreground.webp
│ │ ├── values-night
│ │ │ └── themes.xml
│ │ ├── values
│ │ │ ├── ic_launcher_background.xml
│ │ │ ├── styles.xml
│ │ │ ├── themes.xml
│ │ │ └── strings.xml
│ │ ├── mipmap-anydpi-v26
│ │ │ ├── ic_launcher.xml
│ │ │ └── ic_launcher_round.xml
│ │ ├── menu
│ │ │ └── menu.xml
│ │ ├── xml
│ │ │ ├── backup_rules.xml
│ │ │ ├── data_extraction_rules.xml
│ │ │ └── root_preferences.xml
│ │ └── layout
│ │ │ ├── fragment_watch.xml
│ │ │ └── activity_main.xml
│ │ ├── AndroidManifest.xml
│ │ └── java
│ │ └── com
│ │ └── jummania
│ │ └── analogue_watch
│ │ ├── MainActivity.kt
│ │ └── fragments
│ │ ├── WatchFragment.kt
│ │ └── SettingsFragment.kt
├── proguard-rules.pro
└── build.gradle.kts
├── AnalogClock
├── .gitignore
├── consumer-rules.pro
├── src
│ └── main
│ │ ├── AndroidManifest.xml
│ │ ├── res
│ │ ├── raw
│ │ │ └── sound.mp3
│ │ └── values
│ │ │ └── attrs.xml
│ │ └── java
│ │ └── com
│ │ └── jummania
│ │ └── AnalogClock.kt
├── proguard-rules.pro
└── build.gradle.kts
├── jitpack.yml
├── gradle
├── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
└── libs.versions.toml
├── .gitignore
├── settings.gradle.kts
├── LICENSE.md
├── gradle.properties
├── gradlew.bat
├── gradlew
└── README.md
/app/.gitignore:
--------------------------------------------------------------------------------
1 | /build
--------------------------------------------------------------------------------
/AnalogClock/.gitignore:
--------------------------------------------------------------------------------
1 | /build
--------------------------------------------------------------------------------
/AnalogClock/consumer-rules.pro:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/AnalogClock/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
49 | * * Created by Jummania on 23,May,2024. 50 | * * Email: sharifuddinjumman@gmail.com 51 | * * Dhaka, Bangladesh. 52 | */ 53 | class AnalogClock @JvmOverloads constructor( 54 | context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0 55 | ) : View(context, attrs, defStyleAttr) { 56 | 57 | // Paint and Rect Objects 58 | private val paint = Paint().also { 59 | // Set stroke cap to round 60 | it.strokeCap = Paint.Cap.ROUND 61 | } 62 | private val rect by lazy { Rect() } // Used for calculating the size and position of drawing elements. 63 | 64 | // Integer Variable 65 | private var seconds = 0 // Current value of seconds on the clock face. 66 | 67 | // Float Variables 68 | private var centerX = 0f // X-coordinate of the center of the clock. 69 | private var centerY = 0f // Y-coordinate of the center of the clock. 70 | private var radius = 0f // Radius of the clock face. 71 | private var minuteMarkerHeight = 72 | setValue(0.05f) // Height of the minute markers relative to the clock radius. 73 | private var hourMarkerHeight = 74 | setValue(0.1f) // Height of the hour markers relative to the clock radius. 75 | private var secondHandHeight = 76 | setValue(0.8f) // Length of the second hand relative to the clock radius. 77 | private var minuteHandHeight = 78 | setValue(0.6f) // Length of the minute hand relative to the clock radius. 79 | private var hourHandHeight = 80 | setValue(0.5f) // Length of the hour hand relative to the clock radius. 81 | private var secondHandWidth = setValue(0.02f) // Width of the second hand. 82 | private var minuteHandWidth = setValue(0.03f) // Width of the minute hand. 83 | private var hourHandWidth = setValue(0.04f) // Width of the hour hand. 84 | private var textSize = 22f.toSP() // Size of the clock text. 85 | private var volume = 0.1f // Volume level for the clock ticking sound. 86 | 87 | // Integer (Color) Variables 88 | private var backgroundColor = getColor("#FEF7FF") // Background color of the clock face. 89 | private var minuteMarkerColor = getColor("#1D1B20") // Color of the minute markers. 90 | private var hourMarkerColor = getColor("#C90000") // Color of the hour markers. 91 | private var secondHandColor = hourMarkerColor // Color of the second hand. 92 | private var minuteHandColor = minuteMarkerColor // Color of the minute hand. 93 | private var hourHandColor = minuteMarkerColor // Color of the hour hand. 94 | private var textColor = Color.BLACK // Color of the clock text. 95 | 96 | // Boolean Variables 97 | private var minuteMarker = true // Flag to show/hide minute markers. 98 | private var hourMarker = true // Flag to show/hide hour markers. 99 | private var hourText = true // Flag to show/hide hour numbers. 100 | private var secondHand = true // Flag to show/hide the second hand. 101 | private var minuteHand = true // Flag to show/hide the minute hand. 102 | private var hourHand = true // Flag to show/hide the hour hand. 103 | private var sound = true // Flag to enable/disable clock ticking sound. 104 | private var isReceiverAttached = false // Flag to track if the broadcast receiver is attached. 105 | 106 | // Typeface Variable 107 | private var typeface: Typeface? = null // Typeface for the clock text. 108 | 109 | // MediaPlayer Variable 110 | private var tik1 = 111 | getMediaPlayer(R.raw.sound) // MediaPlayer for playing the clock ticking sound. 112 | set(value) { // Setter for tik1 MediaPlayer. 113 | tik1?.stop() // Stop the currently playing sound. 114 | tik1?.release() // Release system resources associated with the MediaPlayer. 115 | field = value // Assign the new MediaPlayer to the property. 116 | } 117 | 118 | // Handler to schedule periodic updates on the main thread 119 | private val handler = Handler(Looper.getMainLooper()) 120 | 121 | 122 | /** 123 | * Runnable that performs the update of the clock. 124 | * This Runnable is responsible for scheduling periodic updates and invalidating the view to trigger a redraw. 125 | */ 126 | private val updateRunnable = object : Runnable { 127 | override fun run() { 128 | // Remove any pending callbacks to avoid multiple executions 129 | removeCallbacks() 130 | if (secondHand) { 131 | // If the second hand is enabled, schedule the next update in 1000 milliseconds (1 second) 132 | handler.postDelayed(this, 1000) 133 | } 134 | // Redraw the view to update the clock face 135 | invalidate() 136 | } 137 | } 138 | 139 | // BroadcastReceiver to handle external intents 140 | private val timeChangeReceiver = object : BroadcastReceiver() { 141 | override fun onReceive(context: Context?, intent: Intent?) { 142 | removeCallbacks() 143 | updateRunnable.run() 144 | } 145 | } 146 | 147 | 148 | // Initialization block to apply custom attributes from XML 149 | init { 150 | // Obtain the styled attributes from the XML attributes 151 | context.theme.obtainStyledAttributes( 152 | attrs, R.styleable.AnalogClock, defStyleAttr, defStyleAttr 153 | ).use { typedArray -> 154 | // Set background color 155 | setBackgroundColor( 156 | typedArray.getColor( 157 | R.styleable.AnalogClock_background_color, backgroundColor 158 | ) 159 | ) 160 | // Set marker colors 161 | setMarkerColor( 162 | typedArray.getColor( 163 | R.styleable.AnalogClock_minute_marker_color, minuteMarkerColor 164 | ), typedArray.getColor( 165 | R.styleable.AnalogClock_hour_marker_color, hourMarkerColor 166 | ) 167 | ) 168 | // Set hand colors 169 | setHandColor( 170 | typedArray.getColor( 171 | R.styleable.AnalogClock_second_hand_color, secondHandColor 172 | ), typedArray.getColor( 173 | R.styleable.AnalogClock_minute_hand_color, minuteHandColor 174 | ), typedArray.getColor( 175 | R.styleable.AnalogClock_hour_hand_color, hourHandColor 176 | ) 177 | ) 178 | // Set marker heights 179 | setMarkerHeight( 180 | typedArray.getFloat( 181 | R.styleable.AnalogClock_minute_marker_height, minuteMarkerHeight 182 | ), typedArray.getFloat( 183 | R.styleable.AnalogClock_hour_marker_height, hourMarkerHeight 184 | ) 185 | ) 186 | // Set hand lengths 187 | setHandHeight( 188 | typedArray.getFloat( 189 | R.styleable.AnalogClock_second_hand_height, secondHandHeight 190 | ), typedArray.getFloat( 191 | R.styleable.AnalogClock_minute_hand_height, minuteHandHeight 192 | ), typedArray.getFloat( 193 | R.styleable.AnalogClock_hour_hand_height, hourHandHeight 194 | ) 195 | ) 196 | // Set hand widths 197 | setHandWidth( 198 | typedArray.getFloat( 199 | R.styleable.AnalogClock_second_hand_width, secondHandWidth 200 | ), typedArray.getFloat( 201 | R.styleable.AnalogClock_minute_hand_width, minuteHandWidth 202 | ), typedArray.getFloat( 203 | R.styleable.AnalogClock_hour_hand_width, hourHandWidth 204 | ) 205 | ) 206 | // Enable/disable markers 207 | enableMarkers( 208 | typedArray.getBoolean( 209 | R.styleable.AnalogClock_minute_marker, minuteMarker 210 | ), typedArray.getBoolean( 211 | R.styleable.AnalogClock_hour_marker, hourMarker 212 | ) 213 | ) 214 | // Enable/disable hands 215 | enableHands( 216 | typedArray.getBoolean( 217 | R.styleable.AnalogClock_enable_second_hand, secondHand 218 | ), typedArray.getBoolean( 219 | R.styleable.AnalogClock_enable_minute_hand, minuteHand 220 | ), typedArray.getBoolean( 221 | R.styleable.AnalogClock_enable_hour_hand, hourHand 222 | ) 223 | ) 224 | // Enable/disable sound 225 | enableSound( 226 | typedArray.getBoolean( 227 | R.styleable.AnalogClock_enable_sound, sound 228 | ) 229 | ) 230 | // Set volume 231 | setVolume( 232 | typedArray.getFloat( 233 | R.styleable.AnalogClock_volume, volume 234 | ) 235 | ) 236 | // Set MediaPlayer 237 | setMediaPlayer( 238 | typedArray.getResourceId( 239 | R.styleable.AnalogClock_clock_sound, R.raw.sound 240 | ) 241 | ) 242 | // Set Typeface 243 | setTypeface( 244 | Typeface.create( 245 | typedArray.getString(R.styleable.AnalogClock_fontFamily), 246 | typedArray.getInt(R.styleable.AnalogClock_textStyle, 0) 247 | ) 248 | ) 249 | // Set text color 250 | setTextColor( 251 | typedArray.getColor( 252 | R.styleable.AnalogClock_textColor, textColor 253 | ) 254 | ) 255 | // Enable/disable hour text 256 | enableHourText( 257 | typedArray.getBoolean( 258 | R.styleable.AnalogClock_enable_hour_text, hourText 259 | ) 260 | ) 261 | // Set text size 262 | textSize = typedArray.getDimension( 263 | R.styleable.AnalogClock_textSize, textSize 264 | ) 265 | } 266 | 267 | // Schedule the first redraw in 1000 milliseconds 268 | handler.postDelayed(updateRunnable, 1000) 269 | 270 | } 271 | 272 | 273 | /** 274 | * This method is called when the view should render its content. It draws the analog clock face, 275 | * markers, and hands on the canvas. 276 | * 277 | * @param canvas The canvas on which the clock face, markers, and hands are drawn. 278 | */ 279 | override fun onDraw(canvas: Canvas) { 280 | // Calculate center and radius of the clock face 281 | centerX = width / 2f 282 | centerY = height / 2f 283 | radius = min(centerX, centerY) 284 | 285 | // Draw the clock face 286 | drawCircle(canvas, radius, backgroundColor) 287 | 288 | // Create and draw markers (hour and minute) 289 | createMarker(canvas) 290 | 291 | // Create and draw hands (hour, minute, and optionally second) 292 | createHand(canvas) 293 | 294 | // If at least one hand is being drawn, add additional visual elements 295 | } 296 | 297 | 298 | /** 299 | * Called when the visibility of this view and its ancestors change. 300 | * This is used to start or stop the clock updates based on the view's visibility. 301 | * 302 | * @param isVisible True if this view and its ancestors are visible, false otherwise. 303 | */ 304 | override fun onVisibilityAggregated(isVisible: Boolean) { 305 | super.onVisibilityAggregated(isVisible) 306 | // Remove any pending callbacks to ensure no redundant actions 307 | removeCallbacks() 308 | if (isVisible) { 309 | // If the view is visible, start the Runnable to update the clock every second 310 | updateRunnable.run() 311 | // Register the receiver to listen for time tick broadcasts if not already registered 312 | if (!isReceiverAttached) { 313 | context?.registerReceiver(timeChangeReceiver, IntentFilter(Intent.ACTION_TIME_TICK)) 314 | isReceiverAttached = true 315 | } 316 | } else if (isReceiverAttached) { 317 | // If the view is not visible and the receiver is attached, unregister it 318 | context?.unregisterReceiver(timeChangeReceiver) 319 | isReceiverAttached = false 320 | } 321 | } 322 | 323 | 324 | /** 325 | * Draws a circle on the canvas with the specified radius and background color. 326 | * 327 | * @param canvas The canvas on which the circle will be drawn. 328 | * @param radius The radius of the circle. 329 | * @param backgroundColor The background color of the circle. 330 | */ 331 | private fun drawCircle(canvas: Canvas, radius: Float, backgroundColor: Int) { 332 | paint.color = backgroundColor // Set the paint color to the specified background color 333 | canvas.drawCircle(centerX, centerY, radius, paint) // Draw a circle on the canvas 334 | } 335 | 336 | 337 | /** 338 | * Creates and draws markers (hour and minute) on the clock face. 339 | * 340 | * @param canvas The canvas on which the markers will be drawn. 341 | */ 342 | private fun createMarker(canvas: Canvas) { 343 | paint.textSize = textSize * radius * 0.003f // Set the text size for drawing hour numbers 344 | 345 | val padding = 346 | radius - (radius * hourMarkerHeight + paint.textSize / 1.5f) // Calculate padding for hour numbers 347 | 348 | // Iterate through all 60 markers (1 to 60) 349 | for (i in 1..60) { 350 | val angle = i * 6f // Calculate the angle for each marker (6 degrees increment) 351 | 352 | // Check if the marker represents an hour (i.e., divisible by 5) 353 | if (i % 5 == 0) { 354 | // Draw hour marker if enabled 355 | if (hourMarker) { 356 | paint.color = hourMarkerColor // Set the color for hour markers 357 | paint.strokeWidth = 5f // Set the stroke width for drawing lines 358 | createMarker(canvas, radius * hourMarkerHeight, angle) // Draw hour marker 359 | } else createMarker(canvas, angle) // Draw minute marker 360 | 361 | // Draw hour text if enabled 362 | if (hourText) { 363 | val hourText: String = (i / 5).toString() // Convert marker index to hour 364 | paint.getTextBounds( 365 | hourText, 0, hourText.length, rect 366 | ) // Calculate text bounding box 367 | paint.typeface = typeface // Set the typeface for hour numbers 368 | paint.color = textColor // Set the color for hour numbers 369 | 370 | // Calculate position for drawing hour number 371 | val mAngle = Math.PI * i / 30 - Math.PI / 2 372 | val textX = centerX + cos(mAngle) * padding - rect.width() / 2 373 | val textY = centerY + sin(mAngle) * padding + rect.height() / 2 374 | 375 | // Draw hour number on the canvas 376 | canvas.drawText(hourText, textX.toFloat(), textY.toFloat(), paint) 377 | } 378 | } else createMarker(canvas, angle) // Draw minute marker 379 | } 380 | } 381 | 382 | 383 | /** 384 | * Draws a minute marker on the canvas at the specified angle. 385 | * 386 | * @param canvas The Canvas on which the minute marker will be drawn. 387 | * @param angle The angle at which the minute marker will be drawn, in degrees. 388 | */ 389 | private fun createMarker(canvas: Canvas, angle: Float) { 390 | if (minuteMarker) { // Draw minute marker if enabled 391 | paint.color = minuteMarkerColor // Set the color for minute markers 392 | paint.strokeWidth = 3f // Set the stroke width for drawing lines 393 | createMarker(canvas, radius * minuteMarkerHeight, angle) // Draw minute marker 394 | } 395 | } 396 | 397 | 398 | /** 399 | * Draws a marker line on the canvas with the specified length and angle. 400 | * 401 | * @param canvas The canvas on which the marker line will be drawn. 402 | * @param length The length of the marker line. 403 | * @param angle The angle at which the marker line will be drawn. 404 | */ 405 | private fun createMarker(canvas: Canvas, length: Float, angle: Float) { 406 | // Calculate start and end points of the marker line 407 | val markerStartX = centerX + (radius - length) * cos(Math.toRadians(angle.toDouble())) 408 | val markerStartY = centerY + (radius - length) * sin(Math.toRadians(angle.toDouble())) 409 | val markerEndX = centerX + radius * cos(Math.toRadians(angle.toDouble())) 410 | val markerEndY = centerY + radius * sin(Math.toRadians(angle.toDouble())) 411 | 412 | // Draw the marker line on the canvas 413 | canvas.drawLine( 414 | markerStartX.toFloat(), 415 | markerStartY.toFloat(), 416 | markerEndX.toFloat(), 417 | markerEndY.toFloat(), 418 | paint 419 | ) 420 | } 421 | 422 | 423 | /** 424 | * Creates and draws clock hands (hour, minute, and optionally second) on the canvas. 425 | * 426 | * @param canvas The canvas on which the clock hands will be drawn. 427 | * @return A boolean value indicating whether the clock should be redrawn. 428 | */ 429 | private fun createHand(canvas: Canvas) { 430 | // Get the current time 431 | val calendar = Calendar.getInstance() 432 | 433 | val seconds = calendar.get(Calendar.SECOND) 434 | val minutes = calendar.get(Calendar.MINUTE) + seconds / 60.0f 435 | 436 | // Draw hour hand if enabled 437 | if (hourHand) { 438 | createHand( 439 | canvas, 440 | radius * hourHandWidth, 441 | radius * hourHandHeight, 442 | hourHandColor, 443 | (calendar.get(Calendar.HOUR) + minutes / 60.0f) * 5 444 | ) 445 | } 446 | 447 | // Draw minute hand if enabled 448 | if (minuteHand) { 449 | createHand( 450 | canvas, 451 | radius * minuteHandWidth, 452 | radius * minuteHandHeight, 453 | minuteHandColor, 454 | minutes 455 | ) 456 | } 457 | 458 | if (minuteHand || hourHand) { 459 | // Draw a circle if enabled 460 | drawCircle(canvas, radius * hourHandWidth * 1.1f, minuteHandColor) 461 | } 462 | 463 | // Draw second hand if enabled 464 | if (secondHand) { 465 | 466 | // Update seconds and play ticking sound if necessary 467 | if (this.seconds != seconds) { 468 | this.seconds = seconds 469 | if (tik1?.isPlaying == false && sound) { 470 | tik1?.start() 471 | } 472 | } 473 | 474 | createHand( 475 | canvas, 476 | radius * secondHandWidth, 477 | radius * secondHandHeight, 478 | secondHandColor, 479 | seconds.toFloat(), 480 | true 481 | ) 482 | 483 | // Draw a circle 484 | drawCircle(canvas, radius * secondHandWidth * 1.3f, secondHandColor) 485 | } 486 | } 487 | 488 | 489 | /** 490 | * Draws a clock hand on the canvas with the specified width, height, extra line length, color, and angle. 491 | * 492 | * @param canvas The canvas on which the clock hand will be drawn. 493 | * @param width The width of the clock hand. 494 | * @param height The height of the clock hand. 495 | * @param backgroundColor The background color of the clock hand. 496 | * @param angle The angle at which the clock hand will be drawn. 497 | * * @param isSecondHand The hand is second Hand or not. 498 | */ 499 | private fun createHand( 500 | canvas: Canvas, 501 | width: Float, 502 | height: Float, 503 | backgroundColor: Int, 504 | angle: Float, 505 | isSecondHand: Boolean = false 506 | ) { 507 | paint.color = backgroundColor // Set the color of the clock hand 508 | paint.strokeWidth = width // Set the width of the clock hand 509 | // Convert angle to radians 510 | val mAngle = Math.PI * angle / 30 - Math.PI / 2 511 | 512 | val angleX = (cos(mAngle) * height).toFloat() 513 | val angleY = (sin(mAngle) * height).toFloat() 514 | 515 | if (isSecondHand) { 516 | // Draw the line behind the center 517 | canvas.drawLine( 518 | centerX, centerY, centerX - angleX * 0.2f, centerY - angleY * 0.2f, paint 519 | ) 520 | } 521 | 522 | // Draw the main clock hand 523 | canvas.drawLine(centerX, centerY, centerX + angleX, centerY + angleY, paint) 524 | } 525 | 526 | 527 | /** 528 | * Converts a color code represented as a string to its corresponding integer value. 529 | * 530 | * @param colorCode The color code string to be converted. 531 | * @return The integer representation of the color. 532 | */ 533 | private fun getColor(colorCode: String): Int { 534 | return Color.parseColor(colorCode) 535 | } 536 | 537 | 538 | /** 539 | * Sets the color of minute and hour markers. 540 | * 541 | * @param minuteMarkerColor The color of minute markers. 542 | * @param hourMarkerColor The color of hour markers. 543 | */ 544 | fun setMarkerColor( 545 | minuteMarkerColor: Int = this.minuteMarkerColor, hourMarkerColor: Int = this.hourMarkerColor 546 | ) { 547 | this.minuteMarkerColor = minuteMarkerColor 548 | this.hourMarkerColor = hourMarkerColor 549 | } 550 | 551 | 552 | /** 553 | * Sets the color of second, minute, and hour hands. 554 | * 555 | * @param secondHandColor The color of the second hand. 556 | * @param minuteHandColor The color of the minute hand. 557 | * @param hourHandColor The color of the hour hand. 558 | */ 559 | fun setHandColor( 560 | secondHandColor: Int = this.secondHandColor, 561 | minuteHandColor: Int = this.minuteHandColor, 562 | hourHandColor: Int = this.hourHandColor 563 | ) { 564 | this.secondHandColor = secondHandColor 565 | this.minuteHandColor = minuteHandColor 566 | this.hourHandColor = hourHandColor 567 | } 568 | 569 | 570 | /** 571 | * Creates a MediaPlayer object using the provided resource ID and sets its volume. 572 | * 573 | * @param res The resource ID of the sound file to be played. 574 | * @return The MediaPlayer object. 575 | */ 576 | fun getMediaPlayer(res: Int): MediaPlayer? { 577 | return MediaPlayer.create(context, res)?.also { 578 | it.setVolume(volume, volume) 579 | } 580 | } 581 | 582 | 583 | /** 584 | * Sets the background color of the clock face. 585 | * 586 | * @param color The background color to be set. 587 | */ 588 | override fun setBackgroundColor(color: Int) { 589 | backgroundColor = color 590 | } 591 | 592 | 593 | /** 594 | * Sets the text color for the clock. 595 | * 596 | * @param color The text color to be set. 597 | */ 598 | fun setTextColor(@ColorInt color: Int) { 599 | textColor = color 600 | } 601 | 602 | 603 | /** 604 | * Sets the height of minute and hour markers relative to the clock face radius. 605 | * 606 | * @param minuteMarkerHeight The height of minute markers as a fraction of the clock face radius. 607 | * @param hourMarkerHeight The height of hour markers as a fraction of the clock face radius. 608 | */ 609 | fun setMarkerHeight( 610 | @FloatRange(from = 0.0, to = 1.0) minuteMarkerHeight: Float = this.minuteMarkerHeight, 611 | @FloatRange(from = 0.0, to = 1.0) hourMarkerHeight: Float = this.hourMarkerHeight 612 | ) { 613 | this.minuteMarkerHeight = setValue(minuteMarkerHeight) 614 | this.hourMarkerHeight = setValue(hourMarkerHeight) 615 | } 616 | 617 | 618 | /** 619 | * Sets the height of second, minute, and hour hands relative to the clock face radius. 620 | * 621 | * @param secondHandHeight The height of the second hand as a fraction of the clock face radius. 622 | * @param minuteHandHeight The height of the minute hand as a fraction of the clock face radius. 623 | * @param hourHandHeight The height of the hour hand as a fraction of the clock face radius. 624 | */ 625 | fun setHandHeight( 626 | @FloatRange(from = 0.0, to = 1.0) secondHandHeight: Float = this.secondHandHeight, 627 | @FloatRange(from = 0.0, to = 1.0) minuteHandHeight: Float = this.minuteHandHeight, 628 | @FloatRange(from = 0.0, to = 1.0) hourHandHeight: Float = this.hourHandHeight 629 | ) { 630 | this.secondHandHeight = setValue(secondHandHeight) 631 | this.minuteHandHeight = setValue(minuteHandHeight) 632 | this.hourHandHeight = setValue(hourHandHeight) 633 | } 634 | 635 | 636 | /** 637 | * Sets the width of second, minute, and hour hands relative to the clock face radius. 638 | * 639 | * @param secondHandWidth The width of the second hand as a fraction of the clock face radius. 640 | * @param minuteHandWidth The width of the minute hand as a fraction of the clock face radius. 641 | * @param hourHandWidth The width of the hour hand as a fraction of the clock face radius. 642 | */ 643 | fun setHandWidth( 644 | @FloatRange(from = 0.0, to = 1.0) secondHandWidth: Float = this.secondHandWidth, 645 | @FloatRange(from = 0.0, to = 1.0) minuteHandWidth: Float = this.minuteHandWidth, 646 | @FloatRange(from = 0.0, to = 1.0) hourHandWidth: Float = this.hourHandWidth 647 | ) { 648 | this.secondHandWidth = setValue(secondHandWidth) 649 | this.minuteHandWidth = setValue(minuteHandWidth) 650 | this.hourHandWidth = setValue(hourHandWidth) 651 | } 652 | 653 | 654 | /** 655 | * Sets the volume level for the ticking sound of the clock. 656 | * The volume level should be in the range of 0.0 to 1.0. 657 | * 658 | * @param volume The volume level to be set. 659 | */ 660 | fun setVolume(@FloatRange(from = 0.0, to = 1.0) volume: Float) { 661 | // Ensure volume is within the valid range 662 | this.volume = if (volume > 1.0f) volume / 100.0f else volume 663 | // Set the volume for the ticking sound 664 | tik1?.setVolume(volume, volume) 665 | } 666 | 667 | 668 | /** 669 | * Sets the text size for the hour numbers displayed on the clock face. 670 | * 671 | * @param size The text size to be set. 672 | */ 673 | fun setTextSize(size: Float) { 674 | textSize = size.toSP() 675 | } 676 | 677 | 678 | /** 679 | * Enables or disables the display of minute and hour markers on the clock face. 680 | * 681 | * @param minuteMarker Indicates whether minute markers should be displayed. 682 | * @param hourMarker Indicates whether hour markers should be displayed. 683 | */ 684 | fun enableMarkers( 685 | minuteMarker: Boolean = this.minuteMarker, hourMarker: Boolean = this.hourMarker 686 | ) { 687 | this.minuteMarker = minuteMarker 688 | this.hourMarker = hourMarker 689 | } 690 | 691 | 692 | /** 693 | * Enables or disables the display of second, minute, and hour hands on the clock face. 694 | * 695 | * @param secondHand Indicates whether the second hand should be displayed. 696 | * @param minuteHand Indicates whether the minute hand should be displayed. 697 | * @param hourHand Indicates whether the hour hand should be displayed. 698 | */ 699 | fun enableHands( 700 | secondHand: Boolean = this.secondHand, 701 | minuteHand: Boolean = this.minuteHand, 702 | hourHand: Boolean = this.hourHand 703 | ) { 704 | this.secondHand = secondHand 705 | this.minuteHand = minuteHand 706 | this.hourHand = hourHand 707 | } 708 | 709 | 710 | /** 711 | * Enables or disables the ticking sound of the clock. 712 | * 713 | * @param enabled Indicates whether the ticking sound should be enabled. 714 | */ 715 | fun enableSound(enabled: Boolean) { 716 | sound = enabled 717 | } 718 | 719 | 720 | /** 721 | * Enables or disables the display of hour numbers on the clock face. 722 | * 723 | * @param enabled Indicates whether hour numbers should be displayed. 724 | */ 725 | fun enableHourText(enabled: Boolean) { 726 | hourText = enabled 727 | } 728 | 729 | 730 | /** 731 | * Sets the MediaPlayer object used for playing clock ticking sound. 732 | * 733 | * @param mediaPlayer The MediaPlayer object to be set. 734 | */ 735 | fun setMediaPlayer(mediaPlayer: MediaPlayer?) { 736 | tik1 = mediaPlayer 737 | } 738 | 739 | 740 | /** 741 | * Sets the MediaPlayer object for playing clock ticking sound using the resource ID. 742 | * 743 | * @param res The resource ID of the sound file to be played. 744 | */ 745 | fun setMediaPlayer(res: Int) { 746 | tik1 = getMediaPlayer(res) 747 | } 748 | 749 | 750 | /** 751 | * Sets the typeface for hour numbers displayed on the clock face. 752 | * 753 | * @param typeface The Typeface object to be set. 754 | */ 755 | fun setTypeface(typeface: Typeface?) { 756 | this.typeface = typeface 757 | } 758 | 759 | 760 | /** 761 | * Adjusts the value to ensure it is within the valid range of 0.0 to 1.0. 762 | * 763 | * @param value The value to be adjusted. 764 | * @return The adjusted value. 765 | */ 766 | private fun setValue(value: Float): Float { 767 | return if (value > 1.0f) value / 100.0f else value 768 | } 769 | 770 | 771 | /** 772 | * Converts a size value from scaled pixels (SP) to pixels (PX). 773 | * 774 | * @return The size value in pixels (PX). 775 | */ 776 | private fun Float.toSP(): Float { 777 | return TypedValue.applyDimension( 778 | TypedValue.COMPLEX_UNIT_SP, this, resources.displayMetrics 779 | ) 780 | } 781 | 782 | 783 | /** 784 | * Removes any pending callbacks and messages related to the updateRunnable from the message queue. 785 | * This method ensures that no scheduled updates will occur after it is called. 786 | */ 787 | private fun removeCallbacks() { 788 | // Remove any pending posts of the updateRunnable from the message queue 789 | removeCallbacks(updateRunnable) 790 | 791 | // Remove any pending callbacks and messages with the specific updateRunnable 792 | handler.removeCallbacksAndMessages(updateRunnable) 793 | 794 | // Remove any pending callbacks and messages with no specific token (all messages) 795 | handler.removeCallbacksAndMessages(null) 796 | } 797 | 798 | 799 | } 800 | 801 | 802 | 803 | 804 | --------------------------------------------------------------------------------