├── .gitignore ├── LICENSE ├── README.md ├── app ├── .circleci │ └── config.yml ├── .gitignore ├── build.gradle ├── libs │ └── clock-release.aar ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── edu │ │ └── arbelkilani │ │ └── eduarbelkilaniclock │ │ └── ExampleInstrumentedTest.java │ ├── main │ ├── AndroidManifest.xml │ ├── java │ │ └── edu │ │ │ └── arbelkilani │ │ │ └── eduarbelkilaniclock │ │ │ ├── ClockFragment.java │ │ │ ├── MainActivity.java │ │ │ ├── StopWatchAdapter.java │ │ │ ├── StopWatchHolder.java │ │ │ ├── StopwatchFragment.java │ │ │ └── TimeCounterFragment.java │ └── res │ │ ├── drawable-hdpi │ │ ├── ic_clock.png │ │ ├── ic_stopwatch.png │ │ └── ic_time_counter.png │ │ ├── drawable-mdpi │ │ ├── ic_clock.png │ │ ├── ic_stopwatch.png │ │ └── ic_time_counter.png │ │ ├── drawable-v24 │ │ └── ic_launcher_foreground.xml │ │ ├── drawable-xhdpi │ │ ├── ic_clock.png │ │ ├── ic_stopwatch.png │ │ └── ic_time_counter.png │ │ ├── drawable-xxhdpi │ │ ├── ic_clock.png │ │ ├── ic_stopwatch.png │ │ └── ic_time_counter.png │ │ ├── drawable-xxxhdpi │ │ ├── ic_clock.png │ │ ├── ic_stopwatch.png │ │ └── ic_time_counter.png │ │ ├── drawable │ │ ├── background_1.jpg │ │ ├── background_2.jpg │ │ ├── background_3.png │ │ └── ic_launcher_background.xml │ │ ├── font │ │ ├── digital.ttf │ │ ├── hunters.otf │ │ └── texgyretermes_regular.otf │ │ ├── layout │ │ └── activity_main.xml │ │ ├── menu │ │ └── themes.xml │ │ ├── mipmap-anydpi-v26 │ │ ├── ic_launcher.xml │ │ └── ic_launcher_round.xml │ │ ├── mipmap-hdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-mdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-xhdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-xxhdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-xxxhdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ └── values │ │ ├── colors.xml │ │ ├── strings.xml │ │ └── styles.xml │ └── test │ └── java │ └── edu │ └── arbelkilani │ └── eduarbelkilaniclock │ └── ExampleUnitTest.java ├── build.gradle ├── clock ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── com │ │ └── arbelkilani │ │ └── clock │ │ └── ExampleInstrumentedTest.java │ ├── main │ ├── AndroidManifest.xml │ ├── java │ │ └── com │ │ │ └── arbelkilani │ │ │ └── clock │ │ │ ├── Clock.java │ │ │ ├── enumeration │ │ │ ├── BorderStyle.java │ │ │ ├── ClockType.java │ │ │ ├── StopwatchState.java │ │ │ ├── TimeCounterState.java │ │ │ ├── analogical │ │ │ │ ├── DegreeType.java │ │ │ │ ├── DegreesStep.java │ │ │ │ ├── ValueDisposition.java │ │ │ │ ├── ValueStep.java │ │ │ │ └── ValueType.java │ │ │ └── numeric │ │ │ │ └── NumericFormat.java │ │ │ ├── global │ │ │ ├── ClockUtils.java │ │ │ └── ClockViewSaveState.java │ │ │ ├── listener │ │ │ ├── ClockListener.java │ │ │ ├── StopwatchListener.java │ │ │ └── TimeCounterListener.java │ │ │ ├── model │ │ │ ├── StopwatchSavedItem.java │ │ │ └── theme │ │ │ │ ├── AnalogicalTheme.java │ │ │ │ ├── NumericTheme.java │ │ │ │ ├── StopwatchTheme.java │ │ │ │ └── TimeCounterTheme.java │ │ │ └── runnable │ │ │ ├── ClockRunnable.java │ │ │ ├── StopWatchRunnable.java │ │ │ └── TimeCounterRunnable.java │ └── res │ │ ├── font │ │ ├── proxima_nova_regular.otf │ │ └── proxima_nova_thin.otf │ │ └── values │ │ ├── attrs.xml │ │ └── strings.xml │ └── test │ └── java │ └── com │ └── arbelkilani │ └── clock │ └── ExampleUnitTest.java ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── settings.gradle └── wiki ├── analogical ├── bg │ ├── 1.png │ ├── 2.png │ └── 3.png ├── border │ ├── 1.png │ ├── 2.png │ └── 3.png ├── center │ ├── 1.png │ ├── 2.png │ └── 3.png ├── degree │ ├── 1.png │ ├── 2.png │ └── 3.png ├── needle │ ├── 1.png │ ├── 2.png │ └── 3.png ├── progress │ ├── 1.png │ ├── 2.png │ └── 3.png └── values │ ├── 1.png │ ├── 2.png │ └── 3.png ├── clock_cover.png ├── clock_screen.png ├── numeric ├── border │ ├── 1.png │ ├── 2.png │ └── 3.png ├── color │ ├── 1.png │ ├── 2.png │ └── 3.png ├── font │ ├── 1.png │ └── 2.png ├── format │ ├── 1.png │ └── 2.png └── seconds │ ├── 1.png │ └── 2.png ├── stopwatch ├── 1.png ├── 2.png ├── 3.png ├── background │ ├── 1.png │ ├── 2.png │ └── 3.png ├── border │ ├── 1.png │ ├── 2.png │ └── 3.png ├── color │ └── 1.png └── font │ └── 1.png ├── stopwatch_screen.png ├── time_counter ├── 1.png ├── 2.png ├── 3.png ├── background │ ├── 1.png │ └── 2.png ├── border │ ├── 1.png │ ├── 2.png │ └── 3.png ├── color │ ├── 1.png │ └── 2.png └── font │ ├── 1.png │ ├── 2.png │ └── 3.png └── time_counter_screen.png /.gitignore: -------------------------------------------------------------------------------- 1 | # Built application files 2 | *.apk 3 | *.ap_ 4 | 5 | # Files for the ART/Dalvik VM 6 | *.dex 7 | 8 | # Java class files 9 | *.class 10 | 11 | # Generated files 12 | bin/ 13 | gen/ 14 | out/ 15 | 16 | # Gradle files 17 | .gradle/ 18 | build/ 19 | 20 | # Local configuration file (sdk path, etc) 21 | local.properties 22 | 23 | # Proguard folder generated by Eclipse 24 | proguard/ 25 | 26 | # Log Files 27 | *.log 28 | 29 | # Android Studio Navigation editor temp files 30 | .navigation/ 31 | 32 | # Android Studio captures folder 33 | captures/ 34 | 35 | # IntelliJ 36 | *.iml 37 | .idea/workspace.xml 38 | .idea/tasks.xml 39 | .idea/gradle.xml 40 | .idea/assetWizardSettings.xml 41 | .idea/dictionaries 42 | .idea/libraries 43 | .idea/caches 44 | 45 | # Keystore files 46 | # Uncomment the following line if you do not want to check your keystore files in. 47 | #*.jks 48 | 49 | # External native build folder generated in Android Studio 2.2 and later 50 | .externalNativeBuild 51 | 52 | # Google Services (e.g. APIs or Firebase) 53 | google-services.json 54 | 55 | # Freeline 56 | freeline.py 57 | freeline/ 58 | freeline_project_description.json 59 | 60 | # fastlane 61 | fastlane/report.xml 62 | fastlane/Preview.html 63 | fastlane/screenshots 64 | fastlane/test_output 65 | fastlane/readme.md 66 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Clock View 2 | [![Codacy Badge](https://api.codacy.com/project/badge/Grade/cd4176b8e8734648b9e08d4357470c74)](https://app.codacy.com/app/arbelkilani/Clock-view?utm_source=github.com&utm_medium=referral&utm_content=arbelkilani/Clock-view&utm_campaign=Badge_Grade_Dashboard) 3 | [![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://github.com/vlad1m1r990/Lemniscate/blob/master/LICENSE) 4 | [![minSdkVersion](https://img.shields.io/badge/minSdkVersion-21-orange.svg)]() 5 | [![targetSdkVersion](https://img.shields.io/badge/targetSdkVersion-28-yellowgreen.svg)]() 6 | [![](https://jitpack.io/v/arbelkilani/Clock-view.svg)](https://jitpack.io/#arbelkilani/Clock-view) 7 | 8 | ![cover](https://raw.githubusercontent.com/arbelkilani/Clock-view/master/wiki/clock_cover.png) 9 | 10 | Full options Clock view.

You are now able to create and design your own clock view with changing just attributes.
Over 20 attributes are available.

11 | 12 | For all details check [wiki](https://github.com/arbelkilani/Clock-view/wiki) section 13 | 14 | ## Credits 15 | Developed by : [Belkilani Ahmed Radhouane](https://www.linkedin.com/in/arbelkilani/) 16 |
17 | Inspired and based on [Souissi Dorsaf](https://www.behance.net/souissidor8b6c) design. 18 | 19 | ## License 20 | 21 | Copyright 2018 Belkilani Ahmed Radhouane 22 | 23 | Licensed under the Apache License, Version 2.0 (the "License"); 24 | you may not use this file except in compliance with the License. 25 | You may obtain a copy of the License at 26 | 27 | http://www.apache.org/licenses/LICENSE-2.0 28 | 29 | Unless required by applicable law or agreed to in writing, software 30 | distributed under the License is distributed on an "AS IS" BASIS, 31 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 32 | See the License for the specific language governing permissions and 33 | limitations under the License. 34 | -------------------------------------------------------------------------------- /app/.circleci/config.yml: -------------------------------------------------------------------------------- 1 | # Java Gradle CircleCI 2.0 configuration file 2 | # 3 | # Check https://circleci.com/docs/2.0/language-java/ for more details 4 | # 5 | version: 2 6 | jobs: 7 | build: 8 | docker: 9 | # specify the version you desire here 10 | - image: circleci/openjdk:8-jdk 11 | 12 | # Specify service dependencies here if necessary 13 | # CircleCI maintains a library of pre-built images 14 | # documented at https://circleci.com/docs/2.0/circleci-images/ 15 | # - image: circleci/postgres:9.4 16 | 17 | working_directory: ~/repo 18 | 19 | environment: 20 | # Customize the JVM maximum heap limit 21 | JVM_OPTS: -Xmx3200m 22 | TERM: dumb 23 | 24 | steps: 25 | - checkout 26 | 27 | # Download and cache dependencies 28 | - restore_cache: 29 | keys: 30 | - v1-dependencies-{{ checksum "build.gradle" }} 31 | # fallback to using the latest cache if no exact match is found 32 | - v1-dependencies- 33 | 34 | - run: gradle dependencies 35 | 36 | - save_cache: 37 | paths: 38 | - ~/.gradle 39 | key: v1-dependencies-{{ checksum "build.gradle" }} 40 | 41 | # run tests! 42 | - run: gradle test 43 | 44 | 45 | -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | android { 4 | compileSdkVersion 29 5 | defaultConfig { 6 | applicationId "edu.arbelkilani.eduarbelkilaniclock" 7 | minSdkVersion 21 8 | targetSdkVersion 29 9 | versionCode 1 10 | versionName "1.1" 11 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" 12 | } 13 | buildTypes { 14 | release { 15 | minifyEnabled false 16 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 17 | } 18 | } 19 | } 20 | 21 | dependencies { 22 | implementation fileTree(include: ['*.jar'], dir: 'libs') 23 | implementation 'androidx.appcompat:appcompat:1.1.0' 24 | implementation 'androidx.constraintlayout:constraintlayout:1.1.3' 25 | 26 | implementation 'androidx.coordinatorlayout:coordinatorlayout:1.1.0' 27 | implementation 'com.google.android.material:material:1.0.0' 28 | 29 | 30 | implementation 'androidx.legacy:legacy-support-v4:1.0.0' 31 | testImplementation 'junit:junit:4.12' 32 | androidTestImplementation 'androidx.test.ext:junit:1.1.1' 33 | androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0' 34 | //implementation files('libs/clock-release.aar') 35 | implementation project(path: ':clock') 36 | } 37 | -------------------------------------------------------------------------------- /app/libs/clock-release.aar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arbelkilani/Clock-view/6ccea2253b76a65db03fcff1353b551a3d9ed0e6/app/libs/clock-release.aar -------------------------------------------------------------------------------- /app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # You can control the set of applied configuration files using the 3 | # proguardFiles setting in build.gradle. 4 | # 5 | # For more details, see 6 | # http://developer.android.com/guide/developing/tools/proguard.html 7 | 8 | # If your project uses WebView with JS, uncomment the following 9 | # and specify the fully qualified class name to the JavaScript interface 10 | # class: 11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 12 | # public *; 13 | #} 14 | 15 | # Uncomment this to preserve the line number information for 16 | # debugging stack traces. 17 | #-keepattributes SourceFile,LineNumberTable 18 | 19 | # If you keep the line number information, uncomment this to 20 | # hide the original source file name. 21 | #-renamesourcefileattribute SourceFile 22 | -------------------------------------------------------------------------------- /app/src/androidTest/java/edu/arbelkilani/eduarbelkilaniclock/ExampleInstrumentedTest.java: -------------------------------------------------------------------------------- 1 | package edu.arbelkilani.eduarbelkilaniclock; 2 | 3 | import android.content.Context; 4 | 5 | import androidx.test.ext.junit.runners.AndroidJUnit4; 6 | import androidx.test.platform.app.InstrumentationRegistry; 7 | 8 | import org.junit.Test; 9 | import org.junit.runner.RunWith; 10 | 11 | import static org.junit.Assert.assertEquals; 12 | 13 | /** 14 | * Instrumented test, which will execute on an Android device. 15 | * 16 | * @see Testing documentation 17 | */ 18 | @RunWith(AndroidJUnit4.class) 19 | public class ExampleInstrumentedTest { 20 | @Test 21 | public void useAppContext() { 22 | // Context of the app under test. 23 | Context appContext = InstrumentationRegistry.getTargetContext(); 24 | 25 | assertEquals("edu.arbelkilani.eduarbelkilaniclock", appContext.getPackageName()); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /app/src/main/java/edu/arbelkilani/eduarbelkilaniclock/ClockFragment.java: -------------------------------------------------------------------------------- 1 | package edu.arbelkilani.eduarbelkilaniclock; 2 | 3 | 4 | import android.os.Bundle; 5 | 6 | import androidx.fragment.app.Fragment; 7 | 8 | import android.view.LayoutInflater; 9 | import android.view.View; 10 | import android.view.ViewGroup; 11 | 12 | 13 | /** 14 | * A simple {@link Fragment} subclass. 15 | */ 16 | public class ClockFragment extends Fragment { 17 | 18 | public ClockFragment() { 19 | // Required empty public constructor 20 | } 21 | 22 | @Override 23 | public View onCreateView(LayoutInflater inflater, ViewGroup container, 24 | Bundle savedInstanceState) { 25 | // Inflate the layout for this fragment 26 | 27 | return inflater.inflate(R.layout.fragment_clock, container, false); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /app/src/main/java/edu/arbelkilani/eduarbelkilaniclock/MainActivity.java: -------------------------------------------------------------------------------- 1 | package edu.arbelkilani.eduarbelkilaniclock; 2 | 3 | import android.os.Bundle; 4 | import android.view.MenuItem; 5 | 6 | import androidx.annotation.NonNull; 7 | import androidx.appcompat.app.ActionBar; 8 | import androidx.appcompat.app.AppCompatActivity; 9 | import androidx.fragment.app.Fragment; 10 | import androidx.fragment.app.FragmentTransaction; 11 | 12 | import com.google.android.material.bottomnavigation.BottomNavigationView; 13 | 14 | public class MainActivity extends AppCompatActivity { 15 | 16 | private ActionBar toolbar; 17 | 18 | private ClockFragment clockFragment; 19 | private StopwatchFragment stopwatchFragment; 20 | private TimeCounterFragment timeCounterFragment; 21 | 22 | @Override 23 | protected void onCreate(Bundle savedInstanceState) { 24 | super.onCreate(savedInstanceState); 25 | setContentView(R.layout.activity_main); 26 | 27 | clockFragment = new ClockFragment(); 28 | stopwatchFragment = new StopwatchFragment(); 29 | timeCounterFragment = new TimeCounterFragment(); 30 | 31 | loadFragment(clockFragment); 32 | toolbar = getSupportActionBar(); 33 | 34 | 35 | BottomNavigationView bottomNavigationView = findViewById(R.id.bottom_navigation); 36 | bottomNavigationView.setOnNavigationItemSelectedListener(new BottomNavigationView.OnNavigationItemSelectedListener() { 37 | @Override 38 | public boolean onNavigationItemSelected(@NonNull MenuItem menuItem) { 39 | switch (menuItem.getItemId()) { 40 | 41 | case R.id.clock: 42 | loadFragment(clockFragment); 43 | toolbar.setTitle(R.string.clock); 44 | return true; 45 | 46 | case R.id.stopwatch: 47 | loadFragment(stopwatchFragment); 48 | toolbar.setTitle(R.string.stopwatch); 49 | return true; 50 | 51 | case R.id.time_counter: 52 | loadFragment(timeCounterFragment); 53 | toolbar.setTitle(R.string.time_counter); 54 | return true; 55 | } 56 | 57 | return false; 58 | } 59 | }); 60 | 61 | toolbar.setTitle(R.string.clock); 62 | } 63 | 64 | private void loadFragment(Fragment fragment) { 65 | FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginTransaction(); 66 | fragmentTransaction.replace(R.id.frame_container, fragment); 67 | fragmentTransaction.commit(); 68 | } 69 | 70 | } 71 | -------------------------------------------------------------------------------- /app/src/main/java/edu/arbelkilani/eduarbelkilaniclock/StopWatchAdapter.java: -------------------------------------------------------------------------------- 1 | package edu.arbelkilani.eduarbelkilaniclock; 2 | 3 | import android.view.LayoutInflater; 4 | import android.view.View; 5 | import android.view.ViewGroup; 6 | 7 | import androidx.annotation.NonNull; 8 | import androidx.recyclerview.widget.RecyclerView; 9 | 10 | import com.arbelkilani.clock.model.StopwatchSavedItem; 11 | 12 | import java.util.List; 13 | 14 | public class StopWatchAdapter extends RecyclerView.Adapter { 15 | 16 | List savedItemList; 17 | 18 | public StopWatchAdapter(List savedItemList) { 19 | this.savedItemList = savedItemList; 20 | } 21 | 22 | @NonNull 23 | @Override 24 | public StopWatchHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { 25 | LayoutInflater layoutInflater = LayoutInflater.from(parent.getContext()); 26 | View view = layoutInflater.inflate(R.layout.item_stopwatch, parent, false); 27 | return new StopWatchHolder(view); 28 | } 29 | 30 | @Override 31 | public void onBindViewHolder(@NonNull StopWatchHolder holder, int position) { 32 | StopwatchSavedItem stopwatchSavedItem = savedItemList.get(position); 33 | holder.populate(stopwatchSavedItem); 34 | } 35 | 36 | @Override 37 | public int getItemCount() { 38 | return savedItemList.size(); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /app/src/main/java/edu/arbelkilani/eduarbelkilaniclock/StopWatchHolder.java: -------------------------------------------------------------------------------- 1 | package edu.arbelkilani.eduarbelkilaniclock; 2 | 3 | import android.annotation.SuppressLint; 4 | import android.view.View; 5 | import android.widget.TextView; 6 | 7 | import androidx.annotation.NonNull; 8 | import androidx.recyclerview.widget.RecyclerView; 9 | 10 | import com.arbelkilani.clock.model.StopwatchSavedItem; 11 | 12 | import java.text.SimpleDateFormat; 13 | import java.util.Calendar; 14 | import java.util.Locale; 15 | 16 | public class StopWatchHolder extends RecyclerView.ViewHolder { 17 | 18 | private TextView valueTextView, dateTextView, timeTextView; 19 | 20 | public StopWatchHolder(@NonNull View itemView) { 21 | super(itemView); 22 | valueTextView = itemView.findViewById(R.id.value); 23 | dateTextView = itemView.findViewById(R.id.date); 24 | timeTextView = itemView.findViewById(R.id.time); 25 | } 26 | 27 | @SuppressLint("DefaultLocale") 28 | public void populate(StopwatchSavedItem stopwatchSavedItem) { 29 | valueTextView.setText(String.format("%02d:%02d Min", stopwatchSavedItem.getMinutes(), stopwatchSavedItem.getSeconds())); 30 | 31 | SimpleDateFormat simpleDateFormat = new SimpleDateFormat("EEE, MMM d", Locale.ENGLISH); 32 | dateTextView.setText(simpleDateFormat.format(stopwatchSavedItem.getCalendar().getTime())); 33 | 34 | 35 | String time = String.format("%s:%s %s", 36 | String.format(Locale.getDefault(), "%02d", stopwatchSavedItem.getCalendar().get(Calendar.HOUR)), 37 | String.format(Locale.getDefault(), "%02d", stopwatchSavedItem.getCalendar().get(Calendar.MINUTE)), 38 | stopwatchSavedItem.getCalendar().get(Calendar.AM_PM) == Calendar.AM ? "AM" : "PM"); 39 | timeTextView.setText(time); 40 | 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /app/src/main/java/edu/arbelkilani/eduarbelkilaniclock/StopwatchFragment.java: -------------------------------------------------------------------------------- 1 | package edu.arbelkilani.eduarbelkilaniclock; 2 | 3 | 4 | import android.os.Bundle; 5 | 6 | import androidx.annotation.NonNull; 7 | import androidx.fragment.app.Fragment; 8 | import androidx.recyclerview.widget.LinearLayoutManager; 9 | import androidx.recyclerview.widget.RecyclerView; 10 | 11 | import android.util.Log; 12 | import android.view.LayoutInflater; 13 | import android.view.View; 14 | import android.view.ViewGroup; 15 | import android.widget.Button; 16 | 17 | import com.arbelkilani.clock.Clock; 18 | import com.arbelkilani.clock.enumeration.StopwatchState; 19 | import com.arbelkilani.clock.listener.StopwatchListener; 20 | import com.arbelkilani.clock.model.StopwatchSavedItem; 21 | import com.arbelkilani.clock.model.theme.StopwatchTheme; 22 | 23 | import java.util.ArrayList; 24 | import java.util.List; 25 | import java.util.Objects; 26 | 27 | 28 | /** 29 | * A simple {@link Fragment} subclass. 30 | */ 31 | public class StopwatchFragment extends Fragment implements View.OnClickListener, StopwatchListener { 32 | 33 | private final static String TAG = StopwatchFragment.class.getSimpleName(); 34 | 35 | private Clock stopwatch; 36 | private Button startBtn, stopBtn, saveBtn; 37 | private RecyclerView recyclerView; 38 | private List savedItemList; 39 | 40 | public StopwatchFragment() { 41 | // Required empty public constructor 42 | } 43 | 44 | 45 | @Override 46 | public View onCreateView(LayoutInflater inflater, ViewGroup container, 47 | Bundle savedInstanceState) { 48 | View view = inflater.inflate(R.layout.fragment_stopwatch, container, false); 49 | initViews(view); 50 | return view; 51 | } 52 | 53 | private void initViews(View view) { 54 | 55 | stopwatch = view.findViewById(R.id.stopwatch); 56 | stopwatch.setStopwatchListener(this); 57 | 58 | 59 | 60 | savedItemList = new ArrayList<>(); 61 | LinearLayoutManager linearLayoutManager = new LinearLayoutManager(getContext(), RecyclerView.VERTICAL, true); 62 | StopWatchAdapter stopWatchAdapter = new StopWatchAdapter(savedItemList); 63 | 64 | recyclerView = view.findViewById(R.id.rv_values); 65 | recyclerView.setLayoutManager(linearLayoutManager); 66 | recyclerView.setAdapter(stopWatchAdapter); 67 | 68 | startBtn = view.findViewById(R.id.btn_start); 69 | startBtn.setOnClickListener(this); 70 | 71 | stopBtn = view.findViewById(R.id.btn_stop); 72 | stopBtn.setOnClickListener(this); 73 | 74 | saveBtn = view.findViewById(R.id.btn_save); 75 | saveBtn.setOnClickListener(this); 76 | } 77 | 78 | @Override 79 | public void onSaveInstanceState(@NonNull Bundle outState) { 80 | super.onSaveInstanceState(outState); 81 | Log.i(TAG, "onSaveState : " + outState.toString()); 82 | } 83 | 84 | @Override 85 | public void onClick(View view) { 86 | switch (view.getId()) { 87 | case R.id.btn_save: 88 | stopwatch.saveStopwatch(); 89 | break; 90 | 91 | case R.id.btn_start: 92 | startStopWatch(); 93 | break; 94 | 95 | case R.id.btn_stop: 96 | stopStopWatch(); 97 | break; 98 | } 99 | } 100 | 101 | private void stopStopWatch() { 102 | stopwatch.stopStopwatch(); 103 | startBtn.setText(R.string.start); 104 | } 105 | 106 | private void startStopWatch() { 107 | switch (stopwatch.getStopwatchState()) { 108 | case stopped: 109 | stopwatch.runStopwatch(); 110 | startBtn.setText(R.string.pause); 111 | break; 112 | 113 | case running: 114 | stopwatch.pauseStopwatch(); 115 | startBtn.setText(R.string.resume); 116 | break; 117 | 118 | case paused: 119 | stopwatch.resumeStopWatch(); 120 | startBtn.setText(R.string.pause); 121 | break; 122 | } 123 | } 124 | 125 | @Override 126 | public void onStopwatchStateChanged(StopwatchState stopwatchState) { 127 | switch (stopwatchState) { 128 | case paused: 129 | startBtn.setText(R.string.resume); 130 | break; 131 | case running: 132 | startBtn.setText(R.string.pause); 133 | break; 134 | case stopped: 135 | startBtn.setText(R.string.start); 136 | break; 137 | } 138 | } 139 | 140 | @Override 141 | public void onStopwatchSaveValue(StopwatchSavedItem stopwatchSavedItem) { 142 | savedItemList.add(stopwatchSavedItem); 143 | Objects.requireNonNull(recyclerView.getAdapter()).notifyDataSetChanged(); 144 | } 145 | } 146 | -------------------------------------------------------------------------------- /app/src/main/java/edu/arbelkilani/eduarbelkilaniclock/TimeCounterFragment.java: -------------------------------------------------------------------------------- 1 | package edu.arbelkilani.eduarbelkilaniclock; 2 | 3 | 4 | import android.os.Bundle; 5 | 6 | import androidx.fragment.app.Fragment; 7 | 8 | import android.util.Log; 9 | import android.view.LayoutInflater; 10 | import android.view.View; 11 | import android.view.ViewGroup; 12 | import android.widget.Button; 13 | import android.widget.Spinner; 14 | 15 | import com.arbelkilani.clock.Clock; 16 | import com.arbelkilani.clock.enumeration.ClockType; 17 | import com.arbelkilani.clock.enumeration.TimeCounterState; 18 | import com.arbelkilani.clock.listener.TimeCounterListener; 19 | 20 | import java.util.concurrent.TimeUnit; 21 | 22 | 23 | /** 24 | * A simple {@link Fragment} subclass. 25 | */ 26 | public class TimeCounterFragment extends Fragment implements View.OnClickListener, TimeCounterListener { 27 | 28 | private final static String TAG = TimeCounterFragment.class.getSimpleName(); 29 | 30 | private Clock timeCounter; 31 | 32 | private Spinner hoursSpinner, minutesSpinner, secondsSpinner; 33 | Button startButton, stopButton; 34 | 35 | public TimeCounterFragment() { 36 | // Required empty public constructor 37 | } 38 | 39 | 40 | @Override 41 | public View onCreateView(LayoutInflater inflater, ViewGroup container, 42 | Bundle savedInstanceState) { 43 | // Inflate the layout for this fragment 44 | View view = inflater.inflate(R.layout.fragment_time_counter, container, false); 45 | initViews(view); 46 | return view; 47 | } 48 | 49 | private void initViews(View view) { 50 | 51 | timeCounter = view.findViewById(R.id.timeCounter); 52 | timeCounter.setTimeCounterListener(this); 53 | 54 | timeCounter.setClockType(ClockType.time_counter); 55 | 56 | hoursSpinner = view.findViewById(R.id.spinner_hours); 57 | minutesSpinner = view.findViewById(R.id.spinner_minutes); 58 | secondsSpinner = view.findViewById(R.id.spinner_seconds); 59 | 60 | startButton = view.findViewById(R.id.btn_start); 61 | startButton.setOnClickListener(this); 62 | 63 | stopButton = view.findViewById(R.id.btn_stop); 64 | stopButton.setOnClickListener(this); 65 | 66 | } 67 | 68 | 69 | private Long getValue() { 70 | String hours = hoursSpinner.getSelectedItem().toString(); 71 | String minutes = minutesSpinner.getSelectedItem().toString(); 72 | String seconds = secondsSpinner.getSelectedItem().toString(); 73 | 74 | 75 | return TimeUnit.HOURS.toMillis(Long.parseLong(hours)) + 76 | TimeUnit.MINUTES.toMillis(Long.parseLong(minutes)) + 77 | TimeUnit.SECONDS.toMillis(Long.parseLong(seconds)); 78 | } 79 | 80 | @Override 81 | public void onClick(View view) { 82 | switch (view.getId()) { 83 | 84 | case R.id.btn_start: 85 | switch (timeCounter.getTimeCounterState()) { 86 | case running: 87 | timeCounter.pauseTimeCounter(); 88 | break; 89 | 90 | case paused: 91 | timeCounter.resumeTimeCounter(); 92 | break; 93 | 94 | case stopped: 95 | timeCounter.runTimeCounter(getValue()); 96 | break; 97 | } 98 | break; 99 | 100 | case R.id.btn_stop: 101 | timeCounter.stopTimeCounter(); 102 | break; 103 | } 104 | } 105 | 106 | @Override 107 | public void onTimeCounterCompleted() { 108 | Log.i(TAG, "Time counter completed"); 109 | resetTimeCounter(); 110 | } 111 | 112 | 113 | private void resetTimeCounter() { 114 | startButton.setText(R.string.start); 115 | minutesSpinner.setSelection(0, true); 116 | secondsSpinner.setSelection(0, true); 117 | } 118 | 119 | @Override 120 | public void onTimeCounterStateChanged(TimeCounterState timeCounterState) { 121 | switch (timeCounterState) { 122 | case running: 123 | startButton.setText(R.string.pause); 124 | break; 125 | 126 | case stopped: 127 | resetTimeCounter(); 128 | break; 129 | 130 | case paused: 131 | startButton.setText(R.string.resume); 132 | break; 133 | } 134 | } 135 | } 136 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/ic_clock.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arbelkilani/Clock-view/6ccea2253b76a65db03fcff1353b551a3d9ed0e6/app/src/main/res/drawable-hdpi/ic_clock.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/ic_stopwatch.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arbelkilani/Clock-view/6ccea2253b76a65db03fcff1353b551a3d9ed0e6/app/src/main/res/drawable-hdpi/ic_stopwatch.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/ic_time_counter.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arbelkilani/Clock-view/6ccea2253b76a65db03fcff1353b551a3d9ed0e6/app/src/main/res/drawable-hdpi/ic_time_counter.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-mdpi/ic_clock.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arbelkilani/Clock-view/6ccea2253b76a65db03fcff1353b551a3d9ed0e6/app/src/main/res/drawable-mdpi/ic_clock.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-mdpi/ic_stopwatch.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arbelkilani/Clock-view/6ccea2253b76a65db03fcff1353b551a3d9ed0e6/app/src/main/res/drawable-mdpi/ic_stopwatch.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-mdpi/ic_time_counter.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arbelkilani/Clock-view/6ccea2253b76a65db03fcff1353b551a3d9ed0e6/app/src/main/res/drawable-mdpi/ic_time_counter.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-v24/ic_launcher_foreground.xml: -------------------------------------------------------------------------------- 1 | 7 | 12 | 13 | 19 | 22 | 25 | 26 | 27 | 28 | 34 | 35 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/ic_clock.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arbelkilani/Clock-view/6ccea2253b76a65db03fcff1353b551a3d9ed0e6/app/src/main/res/drawable-xhdpi/ic_clock.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/ic_stopwatch.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arbelkilani/Clock-view/6ccea2253b76a65db03fcff1353b551a3d9ed0e6/app/src/main/res/drawable-xhdpi/ic_stopwatch.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/ic_time_counter.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arbelkilani/Clock-view/6ccea2253b76a65db03fcff1353b551a3d9ed0e6/app/src/main/res/drawable-xhdpi/ic_time_counter.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ic_clock.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arbelkilani/Clock-view/6ccea2253b76a65db03fcff1353b551a3d9ed0e6/app/src/main/res/drawable-xxhdpi/ic_clock.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ic_stopwatch.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arbelkilani/Clock-view/6ccea2253b76a65db03fcff1353b551a3d9ed0e6/app/src/main/res/drawable-xxhdpi/ic_stopwatch.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ic_time_counter.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arbelkilani/Clock-view/6ccea2253b76a65db03fcff1353b551a3d9ed0e6/app/src/main/res/drawable-xxhdpi/ic_time_counter.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxxhdpi/ic_clock.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arbelkilani/Clock-view/6ccea2253b76a65db03fcff1353b551a3d9ed0e6/app/src/main/res/drawable-xxxhdpi/ic_clock.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxxhdpi/ic_stopwatch.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arbelkilani/Clock-view/6ccea2253b76a65db03fcff1353b551a3d9ed0e6/app/src/main/res/drawable-xxxhdpi/ic_stopwatch.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxxhdpi/ic_time_counter.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arbelkilani/Clock-view/6ccea2253b76a65db03fcff1353b551a3d9ed0e6/app/src/main/res/drawable-xxxhdpi/ic_time_counter.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/background_1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arbelkilani/Clock-view/6ccea2253b76a65db03fcff1353b551a3d9ed0e6/app/src/main/res/drawable/background_1.jpg -------------------------------------------------------------------------------- /app/src/main/res/drawable/background_2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arbelkilani/Clock-view/6ccea2253b76a65db03fcff1353b551a3d9ed0e6/app/src/main/res/drawable/background_2.jpg -------------------------------------------------------------------------------- /app/src/main/res/drawable/background_3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arbelkilani/Clock-view/6ccea2253b76a65db03fcff1353b551a3d9ed0e6/app/src/main/res/drawable/background_3.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_launcher_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 10 | 15 | 20 | 25 | 30 | 35 | 40 | 45 | 50 | 55 | 60 | 65 | 70 | 75 | 80 | 85 | 90 | 95 | 100 | 105 | 110 | 115 | 120 | 125 | 130 | 135 | 140 | 145 | 150 | 155 | 160 | 165 | 170 | 171 | -------------------------------------------------------------------------------- /app/src/main/res/font/digital.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arbelkilani/Clock-view/6ccea2253b76a65db03fcff1353b551a3d9ed0e6/app/src/main/res/font/digital.ttf -------------------------------------------------------------------------------- /app/src/main/res/font/hunters.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arbelkilani/Clock-view/6ccea2253b76a65db03fcff1353b551a3d9ed0e6/app/src/main/res/font/hunters.otf -------------------------------------------------------------------------------- /app/src/main/res/font/texgyretermes_regular.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arbelkilani/Clock-view/6ccea2253b76a65db03fcff1353b551a3d9ed0e6/app/src/main/res/font/texgyretermes_regular.otf -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 7 | 8 | 13 | 14 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /app/src/main/res/menu/themes.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 9 | 10 | 14 | 15 | 19 | 20 | 24 | 25 | 29 | 30 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arbelkilani/Clock-view/6ccea2253b76a65db03fcff1353b551a3d9ed0e6/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arbelkilani/Clock-view/6ccea2253b76a65db03fcff1353b551a3d9ed0e6/app/src/main/res/mipmap-hdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arbelkilani/Clock-view/6ccea2253b76a65db03fcff1353b551a3d9ed0e6/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arbelkilani/Clock-view/6ccea2253b76a65db03fcff1353b551a3d9ed0e6/app/src/main/res/mipmap-mdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arbelkilani/Clock-view/6ccea2253b76a65db03fcff1353b551a3d9ed0e6/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arbelkilani/Clock-view/6ccea2253b76a65db03fcff1353b551a3d9ed0e6/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arbelkilani/Clock-view/6ccea2253b76a65db03fcff1353b551a3d9ed0e6/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arbelkilani/Clock-view/6ccea2253b76a65db03fcff1353b551a3d9ed0e6/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arbelkilani/Clock-view/6ccea2253b76a65db03fcff1353b551a3d9ed0e6/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arbelkilani/Clock-view/6ccea2253b76a65db03fcff1353b551a3d9ed0e6/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #008577 4 | #00574B 5 | #D81B60 6 | 7 | @android:color/white 8 | @android:color/black 9 | #8E44AD 10 | #00BFFF 11 | #FF0000 12 | #005ea6 13 | #3ebddd 14 | #f3932f 15 | #a1a5ad 16 | 17 | -------------------------------------------------------------------------------- /app/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | Clock View 3 | 4 | Clock 5 | Stopwatch 6 | Time Counter 7 | 8 | 9 | Hello blank fragment 10 | Start 11 | Pause 12 | Resume 13 | Stop 14 | Save 15 | 16 | 17 | 00 18 | 01 19 | 02 20 | 03 21 | 04 22 | 23 | 24 | 25 | 00 26 | 01 27 | 02 28 | 03 29 | 30 | 31 | 32 | 00 33 | 02 34 | 03 35 | 04 36 | 05 37 | 06 38 | 07 39 | 08 40 | 09 41 | 10 42 | 43 | 44 | 45 | -------------------------------------------------------------------------------- /app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /app/src/test/java/edu/arbelkilani/eduarbelkilaniclock/ExampleUnitTest.java: -------------------------------------------------------------------------------- 1 | package edu.arbelkilani.eduarbelkilaniclock; 2 | 3 | import org.junit.Test; 4 | 5 | import static org.junit.Assert.*; 6 | 7 | /** 8 | * Example local unit test, which will execute on the development machine (host). 9 | * 10 | * @see Testing documentation 11 | */ 12 | public class ExampleUnitTest { 13 | @Test 14 | public void addition_isCorrect() { 15 | assertEquals(4, 2 + 2); 16 | } 17 | } -------------------------------------------------------------------------------- /build.gradle: -------------------------------------------------------------------------------- 1 | // Top-level build file where you can add configuration options common to all sub-projects/modules. 2 | 3 | buildscript { 4 | 5 | repositories { 6 | google() 7 | jcenter() 8 | } 9 | dependencies { 10 | classpath 'com.android.tools.build:gradle:3.5.3' 11 | // NOTE: Do not place your application dependencies here; they belong 12 | // in the individual module build.gradle files 13 | } 14 | } 15 | 16 | allprojects { 17 | repositories { 18 | google() 19 | jcenter() 20 | flatDir { 21 | dirs 'libs' 22 | } 23 | } 24 | } 25 | 26 | task clean(type: Delete) { 27 | delete rootProject.buildDir 28 | } 29 | -------------------------------------------------------------------------------- /clock/.gitignore: -------------------------------------------------------------------------------- 1 | # Built application files 2 | *.apk 3 | *.ap_ 4 | 5 | # Files for the ART/Dalvik VM 6 | *.dex 7 | 8 | # Java class files 9 | *.class 10 | 11 | # Generated files 12 | bin/ 13 | gen/ 14 | out/ 15 | 16 | # Gradle files 17 | .gradle/ 18 | build/ 19 | 20 | # Local configuration file (sdk path, etc) 21 | local.properties 22 | 23 | # Proguard folder generated by Eclipse 24 | proguard/ 25 | 26 | # Log Files 27 | *.log 28 | 29 | # Android Studio Navigation editor temp files 30 | .navigation/ 31 | 32 | # Android Studio captures folder 33 | captures/ 34 | 35 | # IntelliJ 36 | *.iml 37 | .idea/workspace.xml 38 | .idea/tasks.xml 39 | .idea/gradle.xml 40 | .idea/assetWizardSettings.xml 41 | .idea/dictionaries 42 | .idea/libraries 43 | .idea/caches 44 | 45 | # Keystore files 46 | # Uncomment the following line if you do not want to check your keystore files in. 47 | #*.jks 48 | 49 | # External native build folder generated in Android Studio 2.2 and later 50 | .externalNativeBuild 51 | 52 | # Google Services (e.g. APIs or Firebase) 53 | google-services.json 54 | 55 | # Freeline 56 | freeline.py 57 | freeline/ 58 | freeline_project_description.json 59 | 60 | # fastlane 61 | fastlane/report.xml 62 | fastlane/Preview.html 63 | fastlane/screenshots 64 | fastlane/test_output 65 | fastlane/readme.md 66 | -------------------------------------------------------------------------------- /clock/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.library' 2 | 3 | android { 4 | compileSdkVersion 29 5 | 6 | 7 | 8 | defaultConfig { 9 | minSdkVersion 21 10 | targetSdkVersion 29 11 | versionCode 1 12 | versionName "1.0" 13 | 14 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" 15 | 16 | } 17 | 18 | buildTypes { 19 | release { 20 | minifyEnabled false 21 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 22 | } 23 | } 24 | 25 | } 26 | 27 | dependencies { 28 | implementation fileTree(dir: 'libs', include: ['*.jar']) 29 | 30 | implementation 'androidx.appcompat:appcompat:1.1.0' 31 | testImplementation 'junit:junit:4.12' 32 | androidTestImplementation 'androidx.test.ext:junit:1.1.1' 33 | androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0' 34 | } 35 | -------------------------------------------------------------------------------- /clock/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # You can control the set of applied configuration files using the 3 | # proguardFiles setting in build.gradle. 4 | # 5 | # For more details, see 6 | # http://developer.android.com/guide/developing/tools/proguard.html 7 | 8 | # If your project uses WebView with JS, uncomment the following 9 | # and specify the fully qualified class name to the JavaScript interface 10 | # class: 11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 12 | # public *; 13 | #} 14 | 15 | # Uncomment this to preserve the line number information for 16 | # debugging stack traces. 17 | #-keepattributes SourceFile,LineNumberTable 18 | 19 | # If you keep the line number information, uncomment this to 20 | # hide the original source file name. 21 | #-renamesourcefileattribute SourceFile 22 | -------------------------------------------------------------------------------- /clock/src/androidTest/java/com/arbelkilani/clock/ExampleInstrumentedTest.java: -------------------------------------------------------------------------------- 1 | package com.arbelkilani.clock; 2 | 3 | import android.content.Context; 4 | 5 | import androidx.test.ext.junit.runners.AndroidJUnit4; 6 | import androidx.test.platform.app.InstrumentationRegistry; 7 | 8 | import org.junit.Test; 9 | import org.junit.runner.RunWith; 10 | 11 | import static org.junit.Assert.assertEquals; 12 | 13 | /** 14 | * Instrumented test, which will execute on an Android device. 15 | * 16 | * @see Testing documentation 17 | */ 18 | @RunWith(AndroidJUnit4.class) 19 | public class ExampleInstrumentedTest { 20 | @Test 21 | public void useAppContext() { 22 | // Context of the app under test. 23 | Context appContext = InstrumentationRegistry.getTargetContext(); 24 | 25 | assertEquals("com.arbelkilani.clock.test", appContext.getPackageName()); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /clock/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | -------------------------------------------------------------------------------- /clock/src/main/java/com/arbelkilani/clock/Clock.java: -------------------------------------------------------------------------------- 1 | package com.arbelkilani.clock; 2 | 3 | import android.content.Context; 4 | import android.content.res.TypedArray; 5 | import android.graphics.Bitmap; 6 | import android.graphics.Canvas; 7 | import android.graphics.Color; 8 | import android.graphics.Paint; 9 | import android.graphics.PorterDuff; 10 | import android.graphics.PorterDuffXfermode; 11 | import android.graphics.Rect; 12 | import android.graphics.RectF; 13 | import android.graphics.Typeface; 14 | import android.graphics.drawable.BitmapDrawable; 15 | import android.graphics.drawable.Drawable; 16 | import android.os.Handler; 17 | import android.os.Parcelable; 18 | import android.os.SystemClock; 19 | import android.text.Layout; 20 | import android.text.SpannableStringBuilder; 21 | import android.text.Spanned; 22 | import android.text.StaticLayout; 23 | import android.text.TextPaint; 24 | import android.text.style.RelativeSizeSpan; 25 | import android.util.AttributeSet; 26 | import android.view.View; 27 | 28 | import androidx.annotation.Nullable; 29 | import androidx.core.content.ContextCompat; 30 | import androidx.core.content.res.ResourcesCompat; 31 | 32 | import com.arbelkilani.clock.enumeration.BorderStyle; 33 | import com.arbelkilani.clock.enumeration.analogical.DegreesStep; 34 | import com.arbelkilani.clock.enumeration.analogical.DegreeType; 35 | import com.arbelkilani.clock.enumeration.ClockType; 36 | import com.arbelkilani.clock.enumeration.analogical.ValueDisposition; 37 | import com.arbelkilani.clock.enumeration.analogical.ValueStep; 38 | import com.arbelkilani.clock.enumeration.analogical.ValueType; 39 | import com.arbelkilani.clock.enumeration.StopwatchState; 40 | import com.arbelkilani.clock.enumeration.TimeCounterState; 41 | import com.arbelkilani.clock.enumeration.numeric.NumericFormat; 42 | import com.arbelkilani.clock.global.ClockViewSaveState; 43 | import com.arbelkilani.clock.global.ClockUtils; 44 | import com.arbelkilani.clock.listener.ClockListener; 45 | import com.arbelkilani.clock.listener.StopwatchListener; 46 | import com.arbelkilani.clock.listener.TimeCounterListener; 47 | import com.arbelkilani.clock.model.theme.AnalogicalTheme; 48 | import com.arbelkilani.clock.model.theme.NumericTheme; 49 | import com.arbelkilani.clock.model.StopwatchSavedItem; 50 | import com.arbelkilani.clock.model.theme.StopwatchTheme; 51 | import com.arbelkilani.clock.model.theme.TimeCounterTheme; 52 | import com.arbelkilani.clock.runnable.ClockRunnable; 53 | 54 | import java.util.Calendar; 55 | import java.util.Locale; 56 | import java.util.TimeZone; 57 | import java.util.concurrent.TimeUnit; 58 | 59 | public class Clock extends View { 60 | 61 | private final static String TAG = Clock.class.getSimpleName(); 62 | 63 | // Constantns 64 | 65 | private static final int DEFAULT_PRIMARY_COLOR = Color.BLACK; 66 | private static final int DEFAULT_SECONDARY_COLOR = Color.LTGRAY; 67 | private static final boolean DEFAULT_STATE = false; 68 | private static final float DEFAULT_BORDER_THICKNESS = 0.015f; 69 | private static final int DEFAULT_BORDER_RADIUS = 20; 70 | private static final int DEFAULT_MIN_RADIUS_ = 10; 71 | private static final int DEFAULT_MAX_RADIUS = 90; 72 | private static final int FULL_ANGLE = 360; 73 | private static final int REGULAR_ANGLE = 90; 74 | private static final int CUSTOM_ALPHA = 140; 75 | private static final int FULL_ALPHA = 255; 76 | private static final float DEFAULT_MINUTES_BORDER_FACTOR = 0.4f; 77 | private static final float DEFAULT_SECONDS_BORDER_FACTOR = 0.9f; 78 | private static final float DEFAULT_DEGREE_STROKE_WIDTH = 0.010f; 79 | private static final float DEFAULT_NEEDLE_STROKE_WIDTH = 0.015f; 80 | private static final float NEEDLE_LENGTH_FACTOR = 0.9f; 81 | private static final float DEFAULT_NEEDLE_START_SPACE = 0.05f; 82 | private static final float DEFAULT_HOURS_VALUES_TEXT_SIZE = 0.08f; 83 | private static final int QUARTER_DEGREE_STEPS = 90; 84 | private static final float MINUTES_TEXT_SIZE = 0.050f; 85 | 86 | // Typed Array 87 | private ClockType clockType; 88 | 89 | private Drawable clockBackground; 90 | 91 | private boolean showCenter; 92 | private int centerInnerColor; 93 | private int centerOuterColor; 94 | 95 | private boolean showBorder; 96 | private int borderColor; 97 | private BorderStyle borderStyle; 98 | private int borderRadiusRx = DEFAULT_BORDER_RADIUS; 99 | private int borderRadiusRy = DEFAULT_BORDER_RADIUS; 100 | 101 | private boolean showSecondsNeedle; 102 | private int needleHoursColor; 103 | private int needleMinutesColor; 104 | private int needleSecondsColor; 105 | 106 | private boolean showProgress; 107 | private int progressColor; 108 | private boolean showMinutesProgress; 109 | private int minutesProgressColor; 110 | private float minutesProgressFactor; 111 | private boolean showSecondsProgress; 112 | private int secondsProgressColor; 113 | private float secondsProgressFactor; 114 | 115 | private boolean showDegrees; 116 | private int degreesColor; 117 | private DegreeType degreesType; 118 | private DegreesStep degreesStep; 119 | 120 | private Typeface valuesFont; 121 | private int valuesColor; 122 | private boolean showHoursValues; 123 | private boolean showMinutesValues; 124 | private float minutesValuesFactor; 125 | private ValueStep valueStep; 126 | private ValueType valueType; 127 | private ValueDisposition valueDisposition; 128 | 129 | private NumericFormat numericFormat; 130 | 131 | private boolean numericShowSeconds; 132 | 133 | // Attributes 134 | private int size, centerX, centerY, radius; 135 | private float defaultThickness; 136 | private RectF defaultRectF; 137 | private ClockRunnable mClockRunnable; 138 | private ClockListener mClockListener; 139 | private Calendar mCalendar; 140 | private Handler mHandler; 141 | 142 | // Stopwatch 143 | private long mStartTime, mMillisecondsTime, mUpdateTime, mTimeBuffer = 0L; 144 | private int mMilliseconds, mSeconds, mMinutes; 145 | private StopwatchState mStopwatchState = StopwatchState.stopped; 146 | private StopwatchListener mStopwatchListener; 147 | 148 | // Time counter 149 | private TimeCounterState mTimeCounterState = TimeCounterState.stopped; 150 | private TimeCounterListener mTimeCounterListener; 151 | private long mTimeCounterValue = 0; 152 | private long mInitialTimeCounter; 153 | 154 | 155 | public Clock(Context context) { 156 | super(context); 157 | setSaveEnabled(true); 158 | init(context, null); 159 | } 160 | 161 | public Clock(Context context, @Nullable AttributeSet attrs) { 162 | super(context, attrs); 163 | setSaveEnabled(true); 164 | init(context, attrs); 165 | } 166 | 167 | public Clock(Context context, @Nullable AttributeSet attrs, int defStyleAttr) { 168 | super(context, attrs, defStyleAttr); 169 | init(context, attrs); 170 | } 171 | 172 | @Override 173 | protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 174 | super.onMeasure(widthMeasureSpec, heightMeasureSpec); 175 | 176 | int size; 177 | int width = getMeasuredWidth(); 178 | int height = getMeasuredHeight(); 179 | int widthWithoutPadding = width - getPaddingLeft() - getPaddingRight(); 180 | int heightWithoutPadding = height - getPaddingTop() - getPaddingBottom(); 181 | size = widthWithoutPadding > heightWithoutPadding ? heightWithoutPadding : widthWithoutPadding; 182 | setMeasuredDimension(size + getPaddingLeft() + getPaddingRight(), size + getPaddingTop() + getPaddingBottom()); 183 | } 184 | 185 | private void init(Context context, AttributeSet attrs) { 186 | mClockRunnable = new ClockRunnable(this); 187 | mHandler = new Handler(); 188 | 189 | TypedArray typedArray = getContext().obtainStyledAttributes(attrs, R.styleable.Clock, 0, 0); 190 | 191 | try { 192 | 193 | this.clockType = ClockType.fromId(typedArray.getInt(R.styleable.Clock_clock_type, ClockType.analogical.getId())); 194 | 195 | this.clockBackground = typedArray.getDrawable(R.styleable.Clock_clock_background); 196 | 197 | this.showCenter = typedArray.getBoolean(R.styleable.Clock_show_center, DEFAULT_STATE); 198 | this.centerInnerColor = typedArray.getColor(R.styleable.Clock_center_inner_color, DEFAULT_PRIMARY_COLOR); 199 | this.centerOuterColor = typedArray.getColor(R.styleable.Clock_center_outer_color, DEFAULT_SECONDARY_COLOR); 200 | 201 | this.showBorder = typedArray.getBoolean(R.styleable.Clock_show_border, DEFAULT_STATE); 202 | this.borderColor = typedArray.getColor(R.styleable.Clock_border_color, DEFAULT_PRIMARY_COLOR); 203 | this.borderStyle = BorderStyle.fromId(typedArray.getInt(R.styleable.Clock_border_style, BorderStyle.rectangle.getId())); 204 | int typedBorderRadiusX = typedArray.getInt(R.styleable.Clock_border_radius_rx, DEFAULT_BORDER_RADIUS); 205 | 206 | if (typedBorderRadiusX > DEFAULT_MIN_RADIUS_ && typedBorderRadiusX < DEFAULT_MAX_RADIUS) { 207 | this.borderRadiusRx = typedBorderRadiusX; 208 | } else { 209 | throw new IllegalArgumentException("border_radius_rx should be in ]" + DEFAULT_MIN_RADIUS_ + "," + DEFAULT_MAX_RADIUS + "["); 210 | } 211 | 212 | int typedBorderRadiusY = typedArray.getInt(R.styleable.Clock_border_radius_ry, DEFAULT_BORDER_RADIUS); 213 | if (typedBorderRadiusY > DEFAULT_MIN_RADIUS_ && typedBorderRadiusY < DEFAULT_MAX_RADIUS) { 214 | this.borderRadiusRy = typedBorderRadiusY; 215 | } else { 216 | throw new IllegalArgumentException("border_radius_ry should be in ]" + DEFAULT_MIN_RADIUS_ + "," + DEFAULT_MAX_RADIUS + "["); 217 | } 218 | 219 | this.showSecondsNeedle = typedArray.getBoolean(R.styleable.Clock_show_seconds_needle, DEFAULT_STATE); 220 | this.needleHoursColor = typedArray.getColor(R.styleable.Clock_hours_needle_color, DEFAULT_PRIMARY_COLOR); 221 | this.needleMinutesColor = typedArray.getColor(R.styleable.Clock_minutes_needle_color, DEFAULT_PRIMARY_COLOR); 222 | this.needleSecondsColor = typedArray.getColor(R.styleable.Clock_seconds_needle_color, DEFAULT_SECONDARY_COLOR); 223 | 224 | this.showProgress = typedArray.getBoolean(R.styleable.Clock_show_progress, DEFAULT_STATE); 225 | this.progressColor = typedArray.getColor(R.styleable.Clock_progress_color, DEFAULT_SECONDARY_COLOR); 226 | 227 | this.showMinutesProgress = typedArray.getBoolean(R.styleable.Clock_show_minutes_progress, DEFAULT_STATE); 228 | this.minutesProgressColor = typedArray.getColor(R.styleable.Clock_minutes_progress_color, DEFAULT_PRIMARY_COLOR); 229 | this.minutesProgressFactor = typedArray.getFloat(R.styleable.Clock_minutes_progress_factor, DEFAULT_MINUTES_BORDER_FACTOR); 230 | 231 | this.showSecondsProgress = typedArray.getBoolean(R.styleable.Clock_show_seconds_progress, DEFAULT_STATE); 232 | this.secondsProgressFactor = typedArray.getFloat(R.styleable.Clock_seconds_progress_factor, DEFAULT_SECONDS_BORDER_FACTOR); 233 | this.secondsProgressColor = typedArray.getColor(R.styleable.Clock_seconds_progress_color, DEFAULT_PRIMARY_COLOR); 234 | 235 | this.showDegrees = typedArray.getBoolean(R.styleable.Clock_show_degree, DEFAULT_STATE); 236 | this.degreesColor = typedArray.getColor(R.styleable.Clock_degree_color, DEFAULT_PRIMARY_COLOR); 237 | this.degreesType = DegreeType.fromId(typedArray.getInt(R.styleable.Clock_degree_type, DegreeType.line.getId())); 238 | this.degreesStep = DegreesStep.fromId(typedArray.getInt(R.styleable.Clock_degree_step, DegreesStep.full.getId())); 239 | 240 | this.valuesFont = ResourcesCompat.getFont(getContext(), typedArray.getResourceId(R.styleable.Clock_values_font, R.font.proxima_nova_thin)); 241 | this.valuesColor = typedArray.getColor(R.styleable.Clock_values_color, DEFAULT_PRIMARY_COLOR); 242 | this.showHoursValues = typedArray.getBoolean(R.styleable.Clock_show_hours_values, DEFAULT_STATE); 243 | this.showMinutesValues = typedArray.getBoolean(R.styleable.Clock_show_minutes_value, DEFAULT_STATE); 244 | this.minutesValuesFactor = typedArray.getFloat(R.styleable.Clock_minutes_values_factor, DEFAULT_MINUTES_BORDER_FACTOR); 245 | this.valueStep = ValueStep.fromId(typedArray.getInt(R.styleable.Clock_clock_value_step, ValueStep.full.getId())); 246 | this.valueType = ValueType.fromId(typedArray.getInt(R.styleable.Clock_clock_value_type, ValueType.none.getId())); 247 | this.valueDisposition = ValueDisposition.fromId(typedArray.getInt(R.styleable.Clock_clock_value_disposition, ValueDisposition.regular.getId())); 248 | 249 | this.numericFormat = NumericFormat.fromId(typedArray.getInt(R.styleable.Clock_numeric_format, NumericFormat.hour_12.getId())); 250 | 251 | this.numericShowSeconds = typedArray.getBoolean(R.styleable.Clock_numeric_show_seconds, DEFAULT_STATE); 252 | 253 | typedArray.recycle(); 254 | 255 | } catch (Exception ex) { 256 | ex.printStackTrace(); 257 | } 258 | } 259 | 260 | @Override 261 | protected void onDraw(final Canvas canvas) { 262 | super.onDraw(canvas); 263 | 264 | onPreDraw(canvas); 265 | 266 | mCalendar = Calendar.getInstance(); 267 | 268 | if (mClockListener != null) { 269 | mClockListener.getCalendar(mCalendar); 270 | } 271 | 272 | switch (clockType) { 273 | 274 | case analogical: 275 | drawAnalogicalClock(canvas); 276 | break; 277 | 278 | case numeric: 279 | drawNumericClock(canvas); 280 | break; 281 | 282 | case stopwatch: 283 | drawStopWatch(canvas); 284 | break; 285 | 286 | case time_counter: 287 | drawTimeCounter(canvas); 288 | break; 289 | } 290 | } 291 | 292 | private void drawAnalogicalClock(Canvas canvas) { 293 | drawBackground(canvas); 294 | drawBorder(canvas); 295 | drawHoursValues(canvas); 296 | drawMinutesValues(canvas); 297 | drawDegrees(canvas); 298 | drawNeedles(canvas); 299 | drawCenter(canvas); 300 | } 301 | 302 | private void onPreDraw(Canvas canvas) { 303 | 304 | this.size = getHeight() > getWidth() ? getWidth() : getHeight(); 305 | this.centerX = size / 2; 306 | this.centerY = size / 2; 307 | this.radius = (int) ((this.size * (1 - DEFAULT_BORDER_THICKNESS)) / 2); 308 | 309 | this.defaultThickness = this.size * DEFAULT_BORDER_THICKNESS; 310 | this.defaultRectF = new RectF( 311 | defaultThickness, defaultThickness, 312 | this.size - defaultThickness, this.size - defaultThickness); 313 | 314 | Paint paint = new Paint(); 315 | paint.setColor(Color.BLUE); 316 | paint.setStyle(Paint.Style.STROKE); 317 | paint.setAntiAlias(true); 318 | paint.setStrokeWidth(defaultThickness); 319 | 320 | //canvas.drawRect(new Rect(0, 0, getWidth(), getHeight()), paint); 321 | //canvas.drawCircle(centerX, centerY, radius, paint); 322 | } 323 | 324 | private void drawMinutesValues(Canvas canvas) { 325 | 326 | if (!showMinutesValues) 327 | return; 328 | 329 | Rect rect = new Rect(); 330 | 331 | Typeface typeface = ResourcesCompat.getFont(getContext(), R.font.proxima_nova_thin); 332 | TextPaint textPaint = new TextPaint(); 333 | textPaint.setColor(minutesProgressColor); 334 | textPaint.setTypeface(typeface); 335 | textPaint.setTextSize(size * MINUTES_TEXT_SIZE); 336 | 337 | int rText = (int) (centerX - ((1 - minutesValuesFactor - (2 * DEFAULT_BORDER_THICKNESS) - MINUTES_TEXT_SIZE) * radius)); 338 | 339 | for (int i = 0; i < FULL_ANGLE; i = i + QUARTER_DEGREE_STEPS) { 340 | 341 | int value = i / 6; 342 | String formatted; 343 | switch (valueType) { 344 | 345 | case arabic: 346 | formatted = ClockUtils.toArabic(value); 347 | break; 348 | 349 | case roman: 350 | formatted = ClockUtils.toRoman(value); 351 | break; 352 | 353 | default: 354 | formatted = String.format(Locale.getDefault(), "%02d", value); 355 | break; 356 | } 357 | 358 | int textX = (int) (centerX + rText * Math.cos(Math.toRadians(REGULAR_ANGLE - i))); 359 | int textY = (int) (centerX - rText * Math.sin(Math.toRadians(REGULAR_ANGLE - i))); 360 | textPaint.getTextBounds(formatted, 0, formatted.length(), rect); 361 | canvas.drawText(formatted, textX - rect.width() / formatted.length(), textY + rect.height() / formatted.length(), textPaint); 362 | } 363 | } 364 | 365 | private void drawDegrees(Canvas canvas) { 366 | 367 | if (!showDegrees) 368 | return; 369 | 370 | Paint paint = new Paint(); 371 | paint.setAntiAlias(true); 372 | paint.setStyle(Paint.Style.FILL_AND_STROKE); 373 | paint.setStrokeCap(Paint.Cap.ROUND); 374 | paint.setStrokeWidth(size * DEFAULT_DEGREE_STROKE_WIDTH); 375 | paint.setColor(degreesColor); 376 | 377 | int rPadded = centerX - (int) (size * (DEFAULT_BORDER_THICKNESS + 0.03f)); 378 | int rEnd = centerX - (int) (size * (DEFAULT_BORDER_THICKNESS + 0.06f)); 379 | 380 | for (int i = 0; i < FULL_ANGLE; i = i + degreesStep.getId()) { 381 | 382 | if ((i % REGULAR_ANGLE) != 0 && (i % 15) != 0) 383 | paint.setAlpha(CUSTOM_ALPHA); 384 | else { 385 | paint.setAlpha(FULL_ALPHA); 386 | } 387 | 388 | int startX = (int) (centerX + rPadded * Math.cos(Math.toRadians(i))); 389 | int startY = (int) (centerX - rPadded * Math.sin(Math.toRadians(i))); 390 | 391 | int stopX = (int) (centerX + rEnd * Math.cos(Math.toRadians(i))); 392 | int stopY = (int) (centerX - rEnd * Math.sin(Math.toRadians(i))); 393 | 394 | switch (degreesType) { 395 | 396 | case circle: 397 | canvas.drawCircle(stopX, stopY, size * DEFAULT_DEGREE_STROKE_WIDTH, paint); 398 | break; 399 | 400 | case square: 401 | canvas.drawRect(startX, startY, startX + (size * DEFAULT_DEGREE_STROKE_WIDTH), startY + (size * DEFAULT_DEGREE_STROKE_WIDTH), paint); 402 | break; 403 | 404 | default: 405 | canvas.drawLine(startX, startY, stopX, stopY, paint); 406 | break; 407 | } 408 | } 409 | } 410 | 411 | private void drawTimeCounter(Canvas canvas) { 412 | 413 | Paint paint = new Paint(); 414 | paint.setColor(this.borderColor); 415 | paint.setAntiAlias(true); 416 | 417 | if (clockBackground != null) { 418 | 419 | Bitmap bitmap = ((BitmapDrawable) clockBackground).getBitmap(); 420 | RectF rectF = new RectF(centerX - radius, centerY - radius, centerX + radius, centerY + radius); 421 | 422 | Bitmap output = Bitmap.createBitmap(size, size, Bitmap.Config.ARGB_8888); 423 | Canvas tCanvas = new Canvas(output); 424 | 425 | if (showProgress) { 426 | tCanvas.drawCircle(centerX, centerY, radius, paint); 427 | } else { 428 | switch (borderStyle) { 429 | case rectangle: 430 | tCanvas.drawRect(defaultRectF, paint); 431 | break; 432 | 433 | case circle: 434 | tCanvas.drawCircle(centerX, centerY, radius, paint); 435 | break; 436 | 437 | case rounded_rectangle: 438 | float rx = radius - (radius * (100 - borderRadiusRx)) / 100; 439 | float ry = radius - (radius * (100 - borderRadiusRy)) / 100; 440 | tCanvas.drawRoundRect(defaultRectF, rx, ry, paint); 441 | break; 442 | } 443 | } 444 | 445 | 446 | paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN)); 447 | tCanvas.drawBitmap(bitmap, null, rectF, paint); 448 | canvas.drawBitmap(output, null, rectF, new Paint()); 449 | } 450 | 451 | paint.setStyle(Paint.Style.STROKE); 452 | paint.setStrokeWidth(size * DEFAULT_BORDER_THICKNESS); 453 | 454 | if (showProgress) 455 | canvas.drawCircle(centerX, centerY, radius, paint); 456 | 457 | TextPaint textPaint = new TextPaint(); 458 | textPaint.setTextSize(size * 0.25f); 459 | textPaint.setFlags(Paint.ANTI_ALIAS_FLAG); 460 | textPaint.setAntiAlias(true); 461 | textPaint.setColor(this.valuesColor); 462 | textPaint.setTypeface(this.valuesFont); 463 | 464 | Paint progressArcPaint = new Paint(); 465 | progressArcPaint.setAntiAlias(true); 466 | progressArcPaint.setColor(this.progressColor); 467 | progressArcPaint.setStyle(Paint.Style.STROKE); 468 | progressArcPaint.setStrokeWidth(size * DEFAULT_BORDER_THICKNESS); 469 | progressArcPaint.setStrokeCap(Paint.Cap.ROUND); 470 | 471 | RectF rectF = new RectF(this.centerX - this.radius, this.centerY - this.radius, this.centerX + this.radius, this.centerY + this.radius); 472 | 473 | long timeCounterSweepAngle = (long) ((float) mTimeCounterValue / mInitialTimeCounter * FULL_ANGLE); 474 | if (showProgress) 475 | canvas.drawArc(rectF, -REGULAR_ANGLE, FULL_ANGLE - (FULL_ANGLE - timeCounterSweepAngle), false, progressArcPaint); 476 | 477 | String value = String.format(Locale.getDefault(), "%02d:%02d", 478 | TimeUnit.MILLISECONDS.toMinutes(mTimeCounterValue), 479 | TimeUnit.MILLISECONDS.toSeconds(mTimeCounterValue) - 480 | TimeUnit.MINUTES.toSeconds(TimeUnit.MILLISECONDS.toMinutes(mTimeCounterValue))); 481 | 482 | SpannableStringBuilder spannableString = new SpannableStringBuilder(value); 483 | StaticLayout layout = new StaticLayout(spannableString, textPaint, canvas.getWidth(), Layout.Alignment.ALIGN_CENTER, 1, 1, true); 484 | canvas.translate(this.centerX - layout.getWidth() / 2, this.centerY - layout.getHeight() / 2); 485 | 486 | layout.draw(canvas); 487 | } 488 | 489 | private void drawStopWatch(Canvas canvas) { 490 | 491 | 492 | if (showBorder) { 493 | drawCustomBorder(canvas); 494 | } 495 | 496 | if (clockBackground != null) { 497 | Paint paint = new Paint(); 498 | paint.setAntiAlias(true); 499 | 500 | Bitmap bitmap = ((BitmapDrawable) clockBackground).getBitmap(); 501 | RectF rectF = new RectF(centerX - radius, centerY - radius, centerX + radius, centerY + radius); 502 | 503 | Bitmap output = Bitmap.createBitmap(size, size, Bitmap.Config.ARGB_8888); 504 | Canvas tCanvas = new Canvas(output); 505 | switch (borderStyle) { 506 | case rectangle: 507 | tCanvas.drawRect(defaultRectF, paint); 508 | break; 509 | 510 | case circle: 511 | tCanvas.drawCircle(centerX, centerY, radius, paint); 512 | break; 513 | 514 | case rounded_rectangle: 515 | float rx = radius - (radius * (100 - borderRadiusRx)) / 100; 516 | float ry = radius - (radius * (100 - borderRadiusRy)) / 100; 517 | tCanvas.drawRoundRect(defaultRectF, rx, ry, paint); 518 | break; 519 | } 520 | 521 | paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN)); 522 | tCanvas.drawBitmap(bitmap, null, rectF, paint); 523 | canvas.drawBitmap(output, null, rectF, new Paint()); 524 | } 525 | 526 | 527 | TextPaint textPaint = new TextPaint(); 528 | textPaint.setFlags(Paint.ANTI_ALIAS_FLAG); 529 | textPaint.setAntiAlias(true); 530 | textPaint.setTextSize(size * 0.25f); 531 | textPaint.setColor(this.valuesColor); 532 | textPaint.setTypeface(this.valuesFont); 533 | 534 | String stopwatchValue = String.format(Locale.getDefault(), "%02d", mMinutes) + ":" + String.format(Locale.getDefault(), "%02d", mSeconds); 535 | SpannableStringBuilder spannableString = new SpannableStringBuilder(stopwatchValue); 536 | StaticLayout layout = new StaticLayout(spannableString, textPaint, canvas.getWidth(), Layout.Alignment.ALIGN_CENTER, 1, 1, true); 537 | canvas.translate(centerX - layout.getWidth() / 2, centerY - layout.getHeight() / 2); 538 | 539 | layout.draw(canvas); 540 | } 541 | 542 | private void drawNumericClock(Canvas canvas) { 543 | 544 | if (showBorder) { 545 | drawCustomBorder(canvas); 546 | } 547 | 548 | if (clockBackground != null) { 549 | Paint paint = new Paint(); 550 | paint.setAntiAlias(true); 551 | 552 | Bitmap bitmap = ((BitmapDrawable) clockBackground).getBitmap(); 553 | RectF rectF = new RectF(centerX - radius, centerY - radius, centerX + radius, centerY + radius); 554 | 555 | Bitmap output = Bitmap.createBitmap(size, size, Bitmap.Config.ARGB_8888); 556 | Canvas tCanvas = new Canvas(output); 557 | switch (borderStyle) { 558 | case rectangle: 559 | tCanvas.drawRect(defaultRectF, paint); 560 | break; 561 | 562 | case circle: 563 | tCanvas.drawCircle(centerX, centerY, radius, paint); 564 | break; 565 | 566 | case rounded_rectangle: 567 | float rx = radius - (radius * (100 - borderRadiusRx)) / 100; 568 | float ry = radius - (radius * (100 - borderRadiusRy)) / 100; 569 | tCanvas.drawRoundRect(defaultRectF, rx, ry, paint); 570 | break; 571 | } 572 | 573 | paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN)); 574 | tCanvas.drawBitmap(bitmap, null, rectF, paint); 575 | canvas.drawBitmap(output, null, rectF, new Paint()); 576 | } 577 | 578 | TextPaint textPaint = new TextPaint(); 579 | textPaint.setAntiAlias(true); 580 | textPaint.setTypeface(valuesFont); 581 | 582 | textPaint.setTextSize(size * 0.22f); 583 | textPaint.setColor(this.valuesColor); 584 | 585 | SpannableStringBuilder spannableString = new SpannableStringBuilder(); 586 | 587 | int amPm = mCalendar.get(Calendar.AM_PM); 588 | String minute = String.format(Locale.getDefault(), "%02d", mCalendar.get(Calendar.MINUTE)); 589 | String second = String.format(Locale.getDefault(), "%02d", mCalendar.get(Calendar.SECOND)); 590 | 591 | if (this.numericShowSeconds) { 592 | if (this.numericFormat == NumericFormat.hour_12) { 593 | spannableString.append(String.format(Locale.getDefault(), "%02d", mCalendar.get(Calendar.HOUR))); 594 | spannableString.append(":"); 595 | spannableString.append(minute); 596 | spannableString.append("."); 597 | spannableString.append(second); 598 | spannableString.append(amPm == Calendar.AM ? "AM" : "PM"); 599 | spannableString.setSpan(new RelativeSizeSpan(0.3f), spannableString.toString().length() - 2, spannableString.toString().length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); // se superscript percent 600 | } else { 601 | spannableString.append(String.format(Locale.getDefault(), "%02d", mCalendar.get(Calendar.HOUR_OF_DAY))); 602 | spannableString.append(":"); 603 | spannableString.append(minute); 604 | spannableString.append("."); 605 | spannableString.append(second); 606 | } 607 | } else { 608 | if (this.numericFormat == NumericFormat.hour_12) { 609 | spannableString.append(String.format(Locale.getDefault(), "%02d", mCalendar.get(Calendar.HOUR))); 610 | spannableString.append(":"); 611 | spannableString.append(minute); 612 | spannableString.append(amPm == Calendar.AM ? "AM" : "PM"); 613 | spannableString.setSpan(new RelativeSizeSpan(0.4f), spannableString.toString().length() - 2, spannableString.toString().length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); // se superscript percent 614 | } else { 615 | spannableString.append(String.format(Locale.getDefault(), "%02d", mCalendar.get(Calendar.HOUR_OF_DAY))); 616 | spannableString.append(":"); 617 | spannableString.append(minute); 618 | } 619 | } 620 | 621 | StaticLayout layout = new StaticLayout(spannableString, textPaint, canvas.getWidth(), Layout.Alignment.ALIGN_CENTER, 1, 1, true); 622 | canvas.translate(centerX - layout.getWidth() / 2, centerY - layout.getHeight() / 2); 623 | layout.draw(canvas); 624 | 625 | } 626 | 627 | private void drawCustomBorder(Canvas canvas) { 628 | Paint paint = new Paint(); 629 | paint.setAntiAlias(true); 630 | paint.setStyle(Paint.Style.FILL); 631 | paint.setColor(this.borderColor); 632 | paint.setStyle(Paint.Style.STROKE); 633 | paint.setStrokeWidth(defaultThickness); 634 | 635 | switch (borderStyle) { 636 | case rectangle: 637 | canvas.drawRect(defaultRectF, paint); 638 | break; 639 | 640 | case circle: 641 | canvas.drawCircle(centerX, centerY, radius, paint); 642 | break; 643 | 644 | case rounded_rectangle: 645 | float rx = radius - (radius * (100 - borderRadiusRx)) / 100; 646 | float ry = radius - (radius * (100 - borderRadiusRy)) / 100; 647 | canvas.drawRoundRect(defaultRectF, rx, ry, paint); 648 | break; 649 | } 650 | } 651 | 652 | private void drawHoursValues(Canvas canvas) { 653 | 654 | if (!showHoursValues) 655 | return; 656 | 657 | Rect rect = new Rect(); 658 | 659 | TextPaint textPaint = new TextPaint(); 660 | textPaint.setFlags(Paint.ANTI_ALIAS_FLAG); 661 | textPaint.setAntiAlias(true); 662 | textPaint.setColor(this.valuesColor); 663 | textPaint.setTypeface(this.valuesFont); 664 | textPaint.setTextSize(size * DEFAULT_HOURS_VALUES_TEXT_SIZE); 665 | 666 | float degreeSpace = 0f; 667 | if (showDegrees) 668 | degreeSpace = DEFAULT_DEGREE_STROKE_WIDTH + 0.06f; 669 | 670 | int rText = (int) (centerX - (size * DEFAULT_HOURS_VALUES_TEXT_SIZE) - (size * degreeSpace)); 671 | 672 | for (int i = FULL_ANGLE; i > 0; i = i - valueStep.getId()) { 673 | 674 | int value = i / 30; 675 | String formatted; 676 | switch (valueType) { 677 | 678 | case roman: 679 | formatted = ClockUtils.toRoman(value); 680 | break; 681 | 682 | case arabic: 683 | formatted = ClockUtils.toArabic(value); 684 | break; 685 | 686 | default: 687 | formatted = String.format(Locale.getDefault(), "%02d", value); 688 | break; 689 | } 690 | 691 | if (valueDisposition.getId() == 0) { 692 | if ((i % REGULAR_ANGLE) == 0) { 693 | textPaint.setTextSize(size * DEFAULT_HOURS_VALUES_TEXT_SIZE); 694 | textPaint.setAlpha(FULL_ALPHA); 695 | } else { 696 | textPaint.setTextSize(size * (DEFAULT_HOURS_VALUES_TEXT_SIZE - 0.03f)); 697 | textPaint.setAlpha(CUSTOM_ALPHA); 698 | } 699 | } else { 700 | textPaint.setTextSize(size * DEFAULT_HOURS_VALUES_TEXT_SIZE); 701 | textPaint.setAlpha(FULL_ALPHA); 702 | } 703 | 704 | 705 | int textX = (int) (centerX + rText * Math.cos(Math.toRadians(REGULAR_ANGLE - i))); 706 | int textY = (int) (centerX - rText * Math.sin(Math.toRadians(REGULAR_ANGLE - i))); 707 | textPaint.getTextBounds(formatted, 0, formatted.length(), rect); 708 | canvas.drawText(formatted, textX - rect.width() / formatted.length(), textY + rect.height() / formatted.length(), textPaint); 709 | } 710 | 711 | } 712 | 713 | private void drawNeedles(final Canvas canvas) { 714 | 715 | final Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG); 716 | paint.setStrokeCap(Paint.Cap.ROUND); 717 | paint.setStrokeWidth(size * DEFAULT_NEEDLE_STROKE_WIDTH); 718 | 719 | float needleStartSpace = DEFAULT_NEEDLE_START_SPACE; 720 | 721 | float borderThickness = 0f; 722 | float hoursTextSize = 0f; 723 | float degreesSpace = 0f; 724 | 725 | if (showBorder) 726 | borderThickness = size * DEFAULT_BORDER_THICKNESS; 727 | 728 | if (showHoursValues) 729 | hoursTextSize = size * DEFAULT_HOURS_VALUES_TEXT_SIZE; 730 | 731 | if (showDegrees) 732 | degreesSpace = size * (DEFAULT_BORDER_THICKNESS + 0.06f); // // TODO: 11/7/18 733 | 734 | float needleMaxLength = (radius * NEEDLE_LENGTH_FACTOR) - 2 * (degreesSpace + borderThickness + hoursTextSize); 735 | //float needleMaxLength = (radius * NEEDLE_LENGTH_FACTOR) - (degreesSpace + borderThickness + hoursTextSize); 736 | 737 | // draw seconds needle 738 | float secondsDegree = mCalendar.get(Calendar.SECOND) * 6; 739 | 740 | float startSecondsX = (float) (centerX + (radius * needleStartSpace) * Math.cos(Math.toRadians(-REGULAR_ANGLE + secondsDegree))); 741 | float stopSecondsX = (float) (centerX + needleMaxLength * Math.cos(Math.toRadians(-REGULAR_ANGLE + secondsDegree))); 742 | float startSecondsY = ((float) (centerY + (radius * needleStartSpace) * Math.sin(Math.toRadians(-REGULAR_ANGLE + secondsDegree)))); 743 | float stopSecondsY = ((float) (centerY + needleMaxLength * Math.sin(Math.toRadians(-REGULAR_ANGLE + secondsDegree)))); 744 | 745 | // draw hours needle 746 | float hoursDegree = (mCalendar.get(Calendar.HOUR) + (mCalendar.get(Calendar.MINUTE) / 60f)) * 30; // 30 = 360 / 12 747 | 748 | float startHoursX = (float) (centerX + (radius * needleStartSpace) * Math.cos(Math.toRadians(-REGULAR_ANGLE + hoursDegree))); 749 | float stopHoursX = (float) (centerX + (needleMaxLength * 0.6f) * Math.cos(Math.toRadians(-REGULAR_ANGLE + hoursDegree))); 750 | float startHoursY = ((float) (centerY + (radius * needleStartSpace) * Math.sin(Math.toRadians(-REGULAR_ANGLE + hoursDegree)))); 751 | float stopHoursY = ((float) (centerY + (needleMaxLength * 0.6f) * Math.sin(Math.toRadians(-REGULAR_ANGLE + hoursDegree)))); 752 | 753 | // draw minutes needle 754 | float minutesDegree = (mCalendar.get(Calendar.MINUTE) + (mCalendar.get(Calendar.SECOND) / 60f)) * 6; 755 | 756 | float startMinutesX = (float) (centerX + (radius * needleStartSpace) * Math.cos(Math.toRadians(-REGULAR_ANGLE + minutesDegree))); 757 | float stopMinutesX = (float) (centerX + (needleMaxLength * 0.8f) * Math.cos(Math.toRadians(-REGULAR_ANGLE + minutesDegree))); 758 | float startMinutesY = ((float) (centerY + ((radius - (size * DEFAULT_BORDER_THICKNESS)) * needleStartSpace) * Math.sin(Math.toRadians(-REGULAR_ANGLE + minutesDegree)))); 759 | float stopMinutesY = ((float) (centerY + (needleMaxLength * 0.8f) * Math.sin(Math.toRadians(-REGULAR_ANGLE + minutesDegree)))); 760 | 761 | drawProgressBorder(canvas, hoursDegree, minutesDegree, secondsDegree); 762 | 763 | // hours needle 764 | paint.setColor(needleHoursColor); 765 | canvas.drawLine(startHoursX, startHoursY, stopHoursX, stopHoursY, paint); 766 | 767 | // minutes needle 768 | paint.setColor(needleMinutesColor); 769 | canvas.drawLine(startMinutesX, startMinutesY, stopMinutesX, stopMinutesY, paint); 770 | 771 | // seconds needle 772 | paint.setStrokeWidth(size * 0.008f); 773 | paint.setColor(needleSecondsColor); 774 | if (showSecondsNeedle) { 775 | canvas.drawLine(startSecondsX, startSecondsY, stopSecondsX, stopSecondsY, paint); 776 | } 777 | 778 | } 779 | 780 | private void drawProgressBorder(final Canvas canvas, final float hoursDegree, float minutesDegree, float secondsDegree) { 781 | 782 | float minuteProgressSpace = (radius - DEFAULT_BORDER_THICKNESS) * minutesProgressFactor; 783 | RectF minutesRectF = new RectF(centerX - minuteProgressSpace, centerY - minuteProgressSpace, centerX + minuteProgressSpace, centerY + minuteProgressSpace); 784 | 785 | final RectF hoursRectF = new RectF(centerX - radius, centerY - radius, centerX + radius, centerY + radius); 786 | 787 | float secondsProgressSpace = (radius - DEFAULT_BORDER_THICKNESS) * secondsProgressFactor; 788 | final RectF secondsRectF = new RectF(centerX - secondsProgressSpace, centerY - secondsProgressSpace, centerX + secondsProgressSpace, centerX + secondsProgressSpace); 789 | 790 | final Paint progressArcPaint = new Paint(); 791 | progressArcPaint.setAntiAlias(true); 792 | progressArcPaint.setStyle(Paint.Style.STROKE); 793 | progressArcPaint.setStrokeWidth(size * DEFAULT_BORDER_THICKNESS); 794 | progressArcPaint.setStrokeCap(Paint.Cap.ROUND); 795 | 796 | progressArcPaint.setColor(borderColor); 797 | 798 | if (showSecondsProgress) { 799 | progressArcPaint.setColor(secondsProgressColor); 800 | if (!showProgress) 801 | canvas.drawArc(hoursRectF, -REGULAR_ANGLE, secondsDegree, false, progressArcPaint); 802 | else 803 | canvas.drawArc(secondsRectF, -REGULAR_ANGLE, secondsDegree, false, progressArcPaint); 804 | } 805 | 806 | if (showMinutesProgress) { 807 | progressArcPaint.setColor(borderColor); 808 | canvas.drawCircle(centerX, centerY, minutesRectF.width() / 2, progressArcPaint); 809 | 810 | progressArcPaint.setColor(minutesProgressColor); 811 | canvas.drawArc(minutesRectF, -REGULAR_ANGLE, minutesDegree, false, progressArcPaint); 812 | } 813 | 814 | if (showProgress) { 815 | progressArcPaint.setColor(progressColor); 816 | canvas.drawArc(hoursRectF, -REGULAR_ANGLE, hoursDegree, false, progressArcPaint); 817 | } 818 | 819 | 820 | } 821 | 822 | private void drawBorder(Canvas canvas) { 823 | 824 | if (!showBorder) 825 | return; 826 | 827 | Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG); 828 | paint.setAntiAlias(true); 829 | paint.setColor(this.borderColor); 830 | paint.setStyle(Paint.Style.STROKE); 831 | paint.setStrokeWidth(size * DEFAULT_BORDER_THICKNESS); 832 | canvas.drawCircle(centerX, centerY, radius, paint); 833 | } 834 | 835 | private void drawBackground(Canvas canvas) { 836 | 837 | if (clockBackground == null) 838 | return; 839 | 840 | Bitmap bitmap = ((BitmapDrawable) clockBackground).getBitmap(); 841 | RectF rectF = new RectF(centerX - radius, centerY - radius, centerX + radius, centerY + radius); 842 | 843 | Bitmap output = Bitmap.createBitmap(size, size, Bitmap.Config.ARGB_8888); 844 | Canvas tCanvas = new Canvas(output); 845 | Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG); 846 | tCanvas.drawCircle(centerX, centerY, radius, paint); 847 | paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN)); 848 | tCanvas.drawBitmap(bitmap, null, rectF, paint); 849 | 850 | canvas.drawBitmap(output, null, rectF, new Paint()); 851 | 852 | } 853 | 854 | private void drawCenter(Canvas canvas) { 855 | 856 | if (!showCenter) 857 | return; 858 | 859 | Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG); 860 | 861 | paint.setStyle(Paint.Style.FILL); 862 | paint.setStrokeCap(Paint.Cap.ROUND); 863 | paint.setColor(centerInnerColor); 864 | canvas.drawCircle(centerX, centerY, size * 0.015f, paint); // center 865 | 866 | paint.setStyle(Paint.Style.STROKE); 867 | paint.setColor(centerOuterColor); 868 | paint.setStrokeWidth(size * 0.008f); 869 | canvas.drawCircle(centerX, centerY, size * 0.02f, paint); // border 870 | 871 | } 872 | 873 | @Override 874 | protected void onAttachedToWindow() { 875 | super.onAttachedToWindow(); 876 | if (mClockRunnable != null) 877 | mClockRunnable.run(); 878 | } 879 | 880 | public void setClockListener(ClockListener clockListener) { 881 | mClockListener = clockListener; 882 | } 883 | 884 | public void setStopwatchListener(StopwatchListener stopwatchListener) { 885 | this.mStopwatchListener = stopwatchListener; 886 | } 887 | 888 | public void runStopwatch() { 889 | 890 | mStartTime = SystemClock.uptimeMillis(); 891 | mHandler.postDelayed(stopwatchRunnable, 0); 892 | 893 | mStopwatchState = StopwatchState.running; 894 | if (mStopwatchListener != null) 895 | mStopwatchListener.onStopwatchStateChanged(StopwatchState.running); 896 | } 897 | 898 | Runnable stopwatchRunnable = new Runnable() { 899 | @Override 900 | public void run() { 901 | 902 | mMillisecondsTime = SystemClock.uptimeMillis() - mStartTime; 903 | mUpdateTime = mTimeBuffer + mMillisecondsTime; 904 | 905 | mSeconds = (int) (mUpdateTime / 1000); 906 | mMinutes = mSeconds / 60; 907 | mSeconds = mSeconds % 60; 908 | mMilliseconds = (int) (mUpdateTime % 1000); 909 | 910 | mHandler.postDelayed(this, 0); 911 | postInvalidate(); 912 | } 913 | }; 914 | 915 | public void pauseStopwatch() { 916 | mTimeBuffer += mMillisecondsTime; 917 | removeStopwatchCallback(); 918 | updateStopwatchState(StopwatchState.paused); 919 | } 920 | 921 | private void updateStopwatchState(StopwatchState stopwatchState) { 922 | mStopwatchState = stopwatchState; 923 | if (mStopwatchListener != null) 924 | mStopwatchListener.onStopwatchStateChanged(stopwatchState); 925 | } 926 | 927 | private void updateTimeCounterSate(TimeCounterState timeCounterState) { 928 | mTimeCounterState = timeCounterState; 929 | if (mTimeCounterListener != null) 930 | mTimeCounterListener.onTimeCounterStateChanged(timeCounterState); 931 | } 932 | 933 | public void resumeStopWatch() { 934 | mStartTime = SystemClock.uptimeMillis(); 935 | 936 | stopwatchRunnable.run(); 937 | updateStopwatchState(StopwatchState.running); 938 | } 939 | 940 | public StopwatchState getStopwatchState() { 941 | return mStopwatchState; 942 | } 943 | 944 | public void stopStopwatch() { 945 | mMillisecondsTime = 0L; 946 | mStartTime = 0L; 947 | mTimeBuffer = 0L; 948 | mUpdateTime = 0L; 949 | 950 | mSeconds = 0; 951 | mMinutes = 0; 952 | mMilliseconds = 0; 953 | 954 | removeStopwatchCallback(); 955 | updateStopwatchState(StopwatchState.stopped); 956 | 957 | invalidate(); 958 | } 959 | 960 | private void removeStopwatchCallback() { 961 | mHandler.removeCallbacks(stopwatchRunnable); 962 | new Thread(new Runnable() { 963 | @Override 964 | public void run() { 965 | mHandler.removeCallbacks(stopwatchRunnable); 966 | } 967 | }); 968 | } 969 | 970 | public void saveStopwatch() { 971 | StopwatchSavedItem stopwatchSavedItem = new StopwatchSavedItem(Calendar.getInstance(), mSeconds, mMinutes); 972 | if (mStopwatchListener != null) 973 | mStopwatchListener.onStopwatchSaveValue(stopwatchSavedItem); 974 | } 975 | 976 | public void runTimeCounter(long timeCounterValue) { 977 | if (timeCounterValue == 0) 978 | return; 979 | 980 | mTimeCounterValue = timeCounterValue; 981 | mInitialTimeCounter = timeCounterValue; 982 | mHandler.postDelayed(timeCounterRunnable, 0); 983 | 984 | updateTimeCounterSate(TimeCounterState.running); 985 | } 986 | 987 | Runnable timeCounterRunnable = new Runnable() { 988 | @Override 989 | public void run() { 990 | 991 | mTimeCounterValue = mTimeCounterValue - 1000; 992 | mHandler.postDelayed(this, 1000); 993 | postInvalidate(); 994 | 995 | if (mTimeCounterValue == 0L) { 996 | stopTimeCounter(); 997 | } 998 | } 999 | }; 1000 | 1001 | public TimeCounterState getTimeCounterState() { 1002 | return mTimeCounterState; 1003 | } 1004 | 1005 | public void resumeTimeCounter() { 1006 | timeCounterRunnable.run(); 1007 | updateTimeCounterSate(TimeCounterState.running); 1008 | } 1009 | 1010 | public void pauseTimeCounter() { 1011 | mHandler.removeCallbacks(timeCounterRunnable); 1012 | updateTimeCounterSate(TimeCounterState.paused); 1013 | } 1014 | 1015 | public void stopTimeCounter() { 1016 | 1017 | mInitialTimeCounter = 0L; 1018 | mTimeCounterValue = 0L; 1019 | 1020 | removeTimeCounterCallback(); 1021 | 1022 | updateTimeCounterSate(TimeCounterState.stopped); 1023 | if (mTimeCounterListener != null) 1024 | mTimeCounterListener.onTimeCounterCompleted(); 1025 | 1026 | invalidate(); 1027 | 1028 | } 1029 | 1030 | private void removeTimeCounterCallback() { 1031 | mHandler.removeCallbacks(timeCounterRunnable); 1032 | new Thread(new Runnable() { 1033 | @Override 1034 | public void run() { 1035 | mHandler.removeCallbacks(timeCounterRunnable); 1036 | } 1037 | }); 1038 | } 1039 | 1040 | public void setTimeCounterListener(TimeCounterListener timeCounterListener) { 1041 | mTimeCounterListener = timeCounterListener; 1042 | } 1043 | 1044 | @Nullable 1045 | @Override 1046 | protected Parcelable onSaveInstanceState() { 1047 | 1048 | final Parcelable superState = super.onSaveInstanceState(); 1049 | final ClockViewSaveState clockViewSaveState = new ClockViewSaveState(superState); 1050 | 1051 | // stopwatch 1052 | clockViewSaveState.mSeconds = this.mSeconds; 1053 | clockViewSaveState.mMinutes = this.mMinutes; 1054 | 1055 | clockViewSaveState.mStartTime = this.mStartTime; 1056 | clockViewSaveState.mTimeBuffer = this.mTimeBuffer; 1057 | clockViewSaveState.mMillisecondsTime = this.mMillisecondsTime; 1058 | clockViewSaveState.mStopwatchState = this.mStopwatchState; 1059 | 1060 | if (clockViewSaveState.mStopwatchState == StopwatchState.paused) { 1061 | mTimeBuffer += mMillisecondsTime; 1062 | } 1063 | 1064 | // time counter 1065 | clockViewSaveState.mTimeCounterValue = this.mTimeCounterValue; 1066 | clockViewSaveState.mInitialTimeCounter = this.mInitialTimeCounter; 1067 | clockViewSaveState.mTimeCounterAt = SystemClock.uptimeMillis(); 1068 | clockViewSaveState.mTimeCounterState = this.mTimeCounterState; 1069 | 1070 | return clockViewSaveState; 1071 | } 1072 | 1073 | @Override 1074 | protected void onRestoreInstanceState(Parcelable state) { 1075 | 1076 | final ClockViewSaveState clockViewSaveState = (ClockViewSaveState) state; 1077 | super.onRestoreInstanceState(clockViewSaveState.getSuperState()); 1078 | 1079 | // Stopwatch 1080 | this.mSeconds = clockViewSaveState.mSeconds; 1081 | this.mMinutes = clockViewSaveState.mMinutes; 1082 | 1083 | this.mStartTime = clockViewSaveState.mStartTime; 1084 | this.mTimeBuffer = clockViewSaveState.mTimeBuffer; 1085 | this.mMillisecondsTime = clockViewSaveState.mMillisecondsTime; 1086 | updateStopwatchState(clockViewSaveState.mStopwatchState); 1087 | 1088 | if (this.mStopwatchState == StopwatchState.running) { 1089 | removeStopwatchCallback(); 1090 | mHandler.postDelayed(stopwatchRunnable, 0); 1091 | } 1092 | 1093 | // Time counter 1094 | this.mInitialTimeCounter = clockViewSaveState.mInitialTimeCounter; 1095 | this.mTimeCounterState = clockViewSaveState.mTimeCounterState; 1096 | updateTimeCounterSate(clockViewSaveState.mTimeCounterState); 1097 | if (mTimeCounterState == TimeCounterState.running) { 1098 | this.mTimeCounterValue = clockViewSaveState.mTimeCounterValue - (SystemClock.uptimeMillis() - clockViewSaveState.mTimeCounterAt); 1099 | removeTimeCounterCallback(); 1100 | mHandler.postDelayed(timeCounterRunnable, 0); 1101 | } 1102 | 1103 | if (mTimeCounterState == TimeCounterState.paused) { 1104 | this.mTimeCounterValue = clockViewSaveState.mTimeCounterValue; 1105 | } 1106 | 1107 | invalidate(); 1108 | } 1109 | 1110 | /** 1111 | * Ref : https://garygregory.wordpress.com/2013/06/18/what-are-the-java-timezone-ids/ 1112 | * 1113 | * @param timezoneCountry 1114 | */ 1115 | public void setTimezone(String timezoneCountry) { 1116 | mCalendar = Calendar.getInstance(TimeZone.getTimeZone(timezoneCountry)); 1117 | } 1118 | 1119 | 1120 | // Getters 1121 | 1122 | public ClockType getClockType() { 1123 | return clockType; 1124 | } 1125 | 1126 | 1127 | // Setters 1128 | 1129 | public void setClockType(ClockType clockType) { 1130 | this.clockType = clockType; 1131 | invalidate(); 1132 | } 1133 | 1134 | public void setClockBackground(int clockBackground) { 1135 | this.clockBackground = ResourcesCompat.getDrawable(getContext().getResources(), clockBackground, null); 1136 | } 1137 | 1138 | public void showCenter(boolean showCenter) { 1139 | this.showCenter = showCenter; 1140 | } 1141 | 1142 | public void setCenterInnerColor(int centerInnerColor) { 1143 | this.centerInnerColor = ResourcesCompat.getColor(getContext().getResources(), centerInnerColor, null); 1144 | } 1145 | 1146 | public void setCenterOuterColor(int centerOuterColor) { 1147 | this.centerOuterColor = ResourcesCompat.getColor(getContext().getResources(), centerOuterColor, null); 1148 | } 1149 | 1150 | public void setShowBorder(boolean showBorder) { 1151 | this.showBorder = showBorder; 1152 | } 1153 | 1154 | public void setBorderColor(int borderColor) { 1155 | this.borderColor = ResourcesCompat.getColor(getContext().getResources(), borderColor, null); 1156 | } 1157 | 1158 | public void setBorderStyle(BorderStyle borderStyle) { 1159 | this.borderStyle = borderStyle; 1160 | } 1161 | 1162 | public void setBorderRadius(int borderRadiusRx, int borderRadiusRy) { 1163 | this.borderRadiusRx = borderRadiusRx; 1164 | this.borderRadiusRy = borderRadiusRy; 1165 | } 1166 | 1167 | public void setShowSecondsNeedle(boolean showSecondsNeedle) { 1168 | this.showSecondsNeedle = showSecondsNeedle; 1169 | } 1170 | 1171 | public void setHoursNeedleColor(int needleHoursColor) { 1172 | this.needleHoursColor = ResourcesCompat.getColor(getContext().getResources(), needleHoursColor, null); 1173 | } 1174 | 1175 | public void setMinutesNeedleColor(int needleMinutesColor) { 1176 | this.needleMinutesColor = ResourcesCompat.getColor(getContext().getResources(), needleMinutesColor, null); 1177 | } 1178 | 1179 | public void setSecondsNeedleColor(int needleSecondsColor) { 1180 | this.needleSecondsColor = ResourcesCompat.getColor(getContext().getResources(), needleSecondsColor, null); 1181 | } 1182 | 1183 | public void setShowProgress(boolean showProgress) { 1184 | this.showProgress = showProgress; 1185 | } 1186 | 1187 | public void setProgressColor(int progressColor) { 1188 | this.centerOuterColor = ResourcesCompat.getColor(getContext().getResources(), progressColor, null); 1189 | } 1190 | 1191 | public void setShowMinutesProgress(boolean showMinutesProgress) { 1192 | this.showMinutesProgress = showMinutesProgress; 1193 | } 1194 | 1195 | public void setMinutesProgressColor(int minutesProgressColor) { 1196 | try { 1197 | this.minutesProgressColor = ContextCompat.getColor(getContext(), minutesProgressColor); 1198 | } catch (Exception e) { 1199 | e.printStackTrace(); 1200 | } 1201 | } 1202 | 1203 | public void setMinutesProgressFactor(float minutesProgressFactor) { 1204 | this.minutesProgressFactor = minutesProgressFactor; 1205 | } 1206 | 1207 | public void setShowSecondsProgress(boolean showSecondsProgress) { 1208 | this.showSecondsProgress = showSecondsProgress; 1209 | } 1210 | 1211 | public void setSecondsProgressFactor(float secondsProgressFactor) { 1212 | this.secondsProgressFactor = secondsProgressFactor; 1213 | } 1214 | 1215 | public void setSecondsProgressColor(int secondsProgressColor) { 1216 | try { 1217 | this.secondsProgressColor = ContextCompat.getColor(getContext(), secondsProgressColor); 1218 | } catch (Exception e) { 1219 | e.printStackTrace(); 1220 | } 1221 | } 1222 | 1223 | public void setShowDegrees(boolean showDegrees) { 1224 | this.showDegrees = showDegrees; 1225 | } 1226 | 1227 | public void setDegreesColor(int degreesColor) { 1228 | this.degreesColor = degreesColor; 1229 | } 1230 | 1231 | public void setDegreesType(DegreeType clockDegreesType) { 1232 | this.degreesType = clockDegreesType; 1233 | } 1234 | 1235 | public void setDegreesStep(DegreesStep degreesStep) { 1236 | this.degreesStep = degreesStep; 1237 | } 1238 | 1239 | public void setValuesFont(int valuesFont) { 1240 | this.valuesFont = ResourcesCompat.getFont(getContext(), valuesFont); 1241 | } 1242 | 1243 | public void setValuesColor(int valuesColor) { 1244 | this.valuesColor = ResourcesCompat.getColor(getContext().getResources(), valuesColor, null); 1245 | } 1246 | 1247 | public void setShowHoursValues(boolean showHoursValues) { 1248 | this.showHoursValues = showHoursValues; 1249 | } 1250 | 1251 | public void setShowMinutesValues(boolean showMinutesValues) { 1252 | this.showMinutesValues = showMinutesValues; 1253 | } 1254 | 1255 | public void setMinutesValuesFactor(float minutesValuesFactor) { 1256 | this.minutesValuesFactor = minutesValuesFactor; 1257 | } 1258 | 1259 | public void setValueStep(ValueStep valueStep) { 1260 | this.valueStep = valueStep; 1261 | } 1262 | 1263 | public void setValueType(ValueType valueType) { 1264 | this.valueType = valueType; 1265 | } 1266 | 1267 | public void setValueDisposition(ValueDisposition valueDisposition) { 1268 | this.valueDisposition = valueDisposition; 1269 | } 1270 | 1271 | public void setNumericFormat(NumericFormat numericFormat) { 1272 | this.numericFormat = numericFormat; 1273 | } 1274 | 1275 | public void setNumericShowSeconds(boolean numericShowSeconds) { 1276 | this.numericShowSeconds = numericShowSeconds; 1277 | } 1278 | 1279 | // Themes 1280 | public void setAnalogicalTheme(AnalogicalTheme analogicalTheme) { 1281 | 1282 | this.clockType = analogicalTheme.getClockType(); 1283 | 1284 | this.clockBackground = ResourcesCompat.getDrawable(getContext().getResources(), analogicalTheme.getClockBackground(), null); 1285 | 1286 | this.showCenter = analogicalTheme.isShowCenter(); 1287 | this.centerInnerColor = analogicalTheme.getCenterInnerColor(); 1288 | this.centerOuterColor = analogicalTheme.getCenterOuterColor(); 1289 | 1290 | this.showBorder = analogicalTheme.isShowBorder(); 1291 | this.borderColor = analogicalTheme.getBorderColor(); 1292 | 1293 | this.showSecondsNeedle = analogicalTheme.isShowSecondsNeedle(); 1294 | this.needleHoursColor = analogicalTheme.getNeedleHoursColor(); 1295 | this.needleMinutesColor = analogicalTheme.getNeedleMinutesColor(); 1296 | this.needleSecondsColor = analogicalTheme.getNeedleSecondsColor(); 1297 | 1298 | this.showProgress = analogicalTheme.isShowProgress(); 1299 | this.progressColor = analogicalTheme.getProgressColor(); 1300 | this.showMinutesProgress = analogicalTheme.isShowMinutesProgress(); 1301 | this.minutesProgressColor = analogicalTheme.getMinutesProgressColor(); 1302 | this.minutesProgressFactor = analogicalTheme.getMinutesProgressFactor(); 1303 | this.showSecondsProgress = analogicalTheme.isShowSecondsProgress(); 1304 | this.secondsProgressColor = analogicalTheme.getSecondsProgressColor(); 1305 | this.secondsProgressFactor = analogicalTheme.getSecondsProgressFactor(); 1306 | 1307 | this.showDegrees = analogicalTheme.isShowDegrees(); 1308 | this.degreesColor = ResourcesCompat.getColor(getContext().getResources(), analogicalTheme.getDegreesColor(), null); 1309 | this.degreesType = analogicalTheme.getDegreesType(); 1310 | this.degreesStep = analogicalTheme.getDegreesStep(); 1311 | 1312 | this.valuesFont = ResourcesCompat.getFont(getContext(), analogicalTheme.getValuesFont()); 1313 | this.valuesColor = ResourcesCompat.getColor(getContext().getResources(), analogicalTheme.getValuesColor(), null); 1314 | this.showHoursValues = analogicalTheme.isShowHoursValues(); 1315 | this.showMinutesValues = analogicalTheme.isShowMinutesValues(); 1316 | this.minutesValuesFactor = analogicalTheme.getMinutesValuesFactor(); 1317 | this.valueStep = analogicalTheme.getValueStep(); 1318 | this.valueType = analogicalTheme.getValueType(); 1319 | this.valueDisposition = analogicalTheme.getValueDisposition(); 1320 | } 1321 | 1322 | public void setNumericTheme(NumericTheme numericTheme) { 1323 | 1324 | this.clockType = numericTheme.getClockType(); 1325 | 1326 | this.clockBackground = ResourcesCompat.getDrawable(getContext().getResources(), numericTheme.getClockBackground(), null); 1327 | 1328 | this.valuesFont = ResourcesCompat.getFont(getContext(), numericTheme.getValuesFont()); 1329 | this.valuesColor = ResourcesCompat.getColor(getContext().getResources(), numericTheme.getValuesColor(), null); 1330 | 1331 | this.showBorder = numericTheme.isShowBorder(); 1332 | this.borderColor = numericTheme.getBorderColor(); 1333 | this.borderRadiusRx = numericTheme.getBorderRadiusRx(); 1334 | this.borderRadiusRy = numericTheme.getBorderRadiusRy(); 1335 | 1336 | this.numericFormat = numericTheme.getNumericFormat(); 1337 | } 1338 | 1339 | public void setStopwatchTheme(StopwatchTheme stopwatchTheme) { 1340 | 1341 | this.clockType = stopwatchTheme.getClockType(); 1342 | 1343 | this.clockBackground = ResourcesCompat.getDrawable(getContext().getResources(), stopwatchTheme.getClockBackground(), null); 1344 | 1345 | this.valuesFont = ResourcesCompat.getFont(getContext(), stopwatchTheme.getValuesFont()); 1346 | this.valuesColor = ResourcesCompat.getColor(getContext().getResources(), stopwatchTheme.getValuesColor(), null); 1347 | 1348 | this.showBorder = stopwatchTheme.isShowBorder(); 1349 | this.borderColor = stopwatchTheme.getBorderColor(); 1350 | this.borderRadiusRx = stopwatchTheme.getBorderRadiusRx(); 1351 | this.borderRadiusRy = stopwatchTheme.getBorderRadiusRy(); 1352 | } 1353 | 1354 | public void setTimeCounterTheme(TimeCounterTheme timeCounterTheme) { 1355 | 1356 | this.clockType = timeCounterTheme.getClockType(); 1357 | 1358 | this.clockBackground = ResourcesCompat.getDrawable(getContext().getResources(), timeCounterTheme.getClockBackground(), null); 1359 | 1360 | this.valuesFont = ResourcesCompat.getFont(getContext(), timeCounterTheme.getValuesFont()); 1361 | this.valuesColor = ResourcesCompat.getColor(getContext().getResources(), timeCounterTheme.getValuesColor(), null); 1362 | 1363 | this.showProgress = timeCounterTheme.isShowProgress(); 1364 | this.progressColor = timeCounterTheme.getProgressColor(); 1365 | this.borderColor = timeCounterTheme.getBorderColor(); 1366 | } 1367 | 1368 | } 1369 | -------------------------------------------------------------------------------- /clock/src/main/java/com/arbelkilani/clock/enumeration/BorderStyle.java: -------------------------------------------------------------------------------- 1 | package com.arbelkilani.clock.enumeration; 2 | 3 | public enum BorderStyle { 4 | 5 | rectangle(0), circle(1), rounded_rectangle(2); 6 | 7 | BorderStyle(int i) { 8 | this.id = i; 9 | } 10 | 11 | private int id; 12 | 13 | public int getId() { 14 | return id; 15 | } 16 | 17 | public static BorderStyle fromId(int id) { 18 | for (BorderStyle borderStyle : values()) { 19 | if (borderStyle.id == id) return borderStyle; 20 | } 21 | throw new IllegalArgumentException(); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /clock/src/main/java/com/arbelkilani/clock/enumeration/ClockType.java: -------------------------------------------------------------------------------- 1 | package com.arbelkilani.clock.enumeration; 2 | 3 | public enum ClockType { 4 | 5 | analogical(0), numeric(1), stopwatch(2), time_counter(3); 6 | 7 | ClockType(int i) { 8 | this.id = i; 9 | } 10 | 11 | private int id; 12 | 13 | public int getId() { 14 | return id; 15 | } 16 | 17 | public static ClockType fromId(int id) { 18 | for (ClockType clockType : values()) { 19 | if (clockType.id == id) return clockType; 20 | } 21 | throw new IllegalArgumentException(); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /clock/src/main/java/com/arbelkilani/clock/enumeration/StopwatchState.java: -------------------------------------------------------------------------------- 1 | package com.arbelkilani.clock.enumeration; 2 | 3 | public enum StopwatchState { 4 | running, paused, stopped 5 | } 6 | -------------------------------------------------------------------------------- /clock/src/main/java/com/arbelkilani/clock/enumeration/TimeCounterState.java: -------------------------------------------------------------------------------- 1 | package com.arbelkilani.clock.enumeration; 2 | 3 | public enum TimeCounterState { 4 | running, paused, stopped 5 | } 6 | -------------------------------------------------------------------------------- /clock/src/main/java/com/arbelkilani/clock/enumeration/analogical/DegreeType.java: -------------------------------------------------------------------------------- 1 | package com.arbelkilani.clock.enumeration.analogical; 2 | 3 | public enum DegreeType { 4 | 5 | line(0), circle(1), square(2); 6 | 7 | DegreeType(int i) { 8 | this.id = i; 9 | } 10 | 11 | private int id; 12 | 13 | public int getId() { 14 | return id; 15 | } 16 | 17 | public static DegreeType fromId(int id) { 18 | for (DegreeType clockDegreeType : values()) { 19 | if (clockDegreeType.id == id) return clockDegreeType; 20 | } 21 | throw new IllegalArgumentException(); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /clock/src/main/java/com/arbelkilani/clock/enumeration/analogical/DegreesStep.java: -------------------------------------------------------------------------------- 1 | package com.arbelkilani.clock.enumeration.analogical; 2 | 3 | public enum DegreesStep { 4 | 5 | quarter(90), full(6), twelve(30); 6 | 7 | DegreesStep(int i) { 8 | this.id = i; 9 | } 10 | 11 | private int id; 12 | 13 | public int getId() { 14 | return id; 15 | } 16 | 17 | public static DegreesStep fromId(int id) { 18 | for (DegreesStep degreesStep : values()) { 19 | if (degreesStep.id == id) return degreesStep; 20 | } 21 | throw new IllegalArgumentException(); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /clock/src/main/java/com/arbelkilani/clock/enumeration/analogical/ValueDisposition.java: -------------------------------------------------------------------------------- 1 | package com.arbelkilani.clock.enumeration.analogical; 2 | 3 | public enum ValueDisposition { 4 | 5 | regular(-1), alternate(0); 6 | 7 | ValueDisposition(int i) { 8 | this.id = i; 9 | } 10 | 11 | private int id; 12 | 13 | public int getId() { 14 | return id; 15 | } 16 | 17 | public static ValueDisposition fromId(int id) { 18 | for (ValueDisposition valueDisposition : values()) { 19 | if (valueDisposition.id == id) return valueDisposition; 20 | } 21 | throw new IllegalArgumentException(); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /clock/src/main/java/com/arbelkilani/clock/enumeration/analogical/ValueStep.java: -------------------------------------------------------------------------------- 1 | package com.arbelkilani.clock.enumeration.analogical; 2 | 3 | public enum ValueStep { 4 | 5 | quarter(90), full(30); 6 | 7 | ValueStep(int i) { 8 | this.id = i; 9 | } 10 | 11 | private int id; 12 | 13 | public int getId() { 14 | return id; 15 | } 16 | 17 | public static ValueStep fromId(int id) { 18 | for (ValueStep valueStep : values()) { 19 | if (valueStep.id == id) return valueStep; 20 | } 21 | throw new IllegalArgumentException(); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /clock/src/main/java/com/arbelkilani/clock/enumeration/analogical/ValueType.java: -------------------------------------------------------------------------------- 1 | package com.arbelkilani.clock.enumeration.analogical; 2 | 3 | public enum ValueType { 4 | 5 | none(-1), roman(0), arabic(1); 6 | 7 | ValueType(int i) { 8 | this.id = i; 9 | } 10 | 11 | private int id; 12 | 13 | public int getId() { 14 | return id; 15 | } 16 | 17 | public static ValueType fromId(int id) { 18 | for (ValueType valueType : values()) { 19 | if (valueType.id == id) return valueType; 20 | } 21 | throw new IllegalArgumentException(); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /clock/src/main/java/com/arbelkilani/clock/enumeration/numeric/NumericFormat.java: -------------------------------------------------------------------------------- 1 | package com.arbelkilani.clock.enumeration.numeric; 2 | 3 | public enum NumericFormat { 4 | 5 | hour_12(0), hour_24(1); 6 | 7 | NumericFormat(int i) { 8 | this.id = i; 9 | } 10 | 11 | private int id; 12 | 13 | public int getId() { 14 | return id; 15 | } 16 | 17 | public static NumericFormat fromId(int id) { 18 | for (NumericFormat numericFormat : values()) { 19 | if (numericFormat.id == id) return numericFormat; 20 | } 21 | throw new IllegalArgumentException(); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /clock/src/main/java/com/arbelkilani/clock/global/ClockUtils.java: -------------------------------------------------------------------------------- 1 | package com.arbelkilani.clock.global; 2 | 3 | import java.util.TreeMap; 4 | 5 | public class ClockUtils { 6 | 7 | private final static TreeMap romanMap = new TreeMap(); 8 | private final static TreeMap arabicMap = new TreeMap(); 9 | 10 | static { 11 | 12 | romanMap.put(12, "XII"); 13 | romanMap.put(11, "XI"); 14 | romanMap.put(10, "X"); 15 | romanMap.put(9, "IX"); 16 | 17 | romanMap.put(8, "VIII"); 18 | romanMap.put(7, "VII"); 19 | romanMap.put(6, "VI"); 20 | romanMap.put(5, "V"); 21 | 22 | romanMap.put(4, "IV"); 23 | romanMap.put(3, "III"); 24 | romanMap.put(2, "II"); 25 | romanMap.put(1, "I"); 26 | 27 | } 28 | 29 | static { 30 | 31 | arabicMap.put(12, "١٢"); 32 | arabicMap.put(11, "١١"); 33 | arabicMap.put(10, "١٠\t"); 34 | arabicMap.put(9, "٩"); 35 | 36 | arabicMap.put(8, "٨"); 37 | arabicMap.put(7, "٧"); 38 | arabicMap.put(6, "٦"); 39 | arabicMap.put(5, "٥"); 40 | 41 | arabicMap.put(4, "٤"); 42 | arabicMap.put(3, "٣"); 43 | arabicMap.put(2, "٢"); 44 | arabicMap.put(1, "١"); 45 | 46 | } 47 | 48 | public final static String toRoman(int number) { 49 | int l = romanMap.floorKey(number); 50 | if ( number == l ) { 51 | return romanMap.get(number); 52 | } 53 | return romanMap.get(l) + toRoman(number-l); 54 | } 55 | 56 | public final static String toArabic(int number) { 57 | int l = arabicMap.floorKey(number); 58 | if ( number == l ) { 59 | return arabicMap.get(number); 60 | } 61 | return arabicMap.get(l) + toArabic(number-l); 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /clock/src/main/java/com/arbelkilani/clock/global/ClockViewSaveState.java: -------------------------------------------------------------------------------- 1 | package com.arbelkilani.clock.global; 2 | 3 | import android.os.Parcel; 4 | import android.os.Parcelable; 5 | import android.view.View; 6 | 7 | import com.arbelkilani.clock.enumeration.StopwatchState; 8 | import com.arbelkilani.clock.enumeration.TimeCounterState; 9 | 10 | public class ClockViewSaveState extends View.BaseSavedState { 11 | 12 | // Stopwatch 13 | public int mSeconds; 14 | public int mMinutes; 15 | 16 | public long mStartTime; 17 | public long mTimeBuffer; 18 | public long mMillisecondsTime; 19 | 20 | public StopwatchState mStopwatchState; 21 | 22 | // Time counter 23 | public long mTimeCounterValue; 24 | public long mInitialTimeCounter; 25 | public TimeCounterState mTimeCounterState; 26 | public long mTimeCounterAt; 27 | 28 | public ClockViewSaveState(Parcelable superState) { 29 | super(superState); 30 | } 31 | 32 | public static final Creator CREATOR = new Creator() { 33 | @Override 34 | public ClockViewSaveState createFromParcel(Parcel source) { 35 | return new ClockViewSaveState(source); 36 | } 37 | 38 | @Override 39 | public ClockViewSaveState[] newArray(int size) { 40 | return new ClockViewSaveState[size]; 41 | } 42 | }; 43 | 44 | private ClockViewSaveState(Parcel source) { 45 | super(source); 46 | 47 | mSeconds = source.readInt(); 48 | mMinutes = source.readInt(); 49 | 50 | mStartTime = source.readLong(); 51 | mTimeBuffer = source.readLong(); 52 | mMillisecondsTime = source.readLong(); 53 | 54 | mStopwatchState = StopwatchState.valueOf(source.readString()); 55 | 56 | mTimeCounterValue = source.readLong(); 57 | mInitialTimeCounter = source.readLong(); 58 | mTimeCounterAt = source.readLong(); 59 | mTimeCounterState = TimeCounterState.valueOf(source.readString()); 60 | } 61 | 62 | @Override 63 | public void writeToParcel(Parcel out, int flags) { 64 | super.writeToParcel(out, flags); 65 | 66 | out.writeInt(mSeconds); 67 | out.writeInt(mMinutes); 68 | 69 | out.writeLong(mStartTime); 70 | out.writeLong(mTimeBuffer); 71 | out.writeLong(mMillisecondsTime); 72 | 73 | out.writeString(mStopwatchState.name()); 74 | 75 | out.writeLong(mTimeCounterValue); 76 | out.writeLong(mInitialTimeCounter); 77 | out.writeLong(mTimeCounterAt); 78 | out.writeString(mTimeCounterState.name()); 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /clock/src/main/java/com/arbelkilani/clock/listener/ClockListener.java: -------------------------------------------------------------------------------- 1 | package com.arbelkilani.clock.listener; 2 | 3 | import java.util.Calendar; 4 | 5 | public interface ClockListener { 6 | void getCalendar(Calendar calendar); 7 | } 8 | -------------------------------------------------------------------------------- /clock/src/main/java/com/arbelkilani/clock/listener/StopwatchListener.java: -------------------------------------------------------------------------------- 1 | package com.arbelkilani.clock.listener; 2 | 3 | import com.arbelkilani.clock.enumeration.StopwatchState; 4 | import com.arbelkilani.clock.model.StopwatchSavedItem; 5 | 6 | public interface StopwatchListener { 7 | 8 | void onStopwatchStateChanged(StopwatchState stopwatchState); 9 | 10 | void onStopwatchSaveValue(StopwatchSavedItem stopwatchSavedItem); 11 | } 12 | -------------------------------------------------------------------------------- /clock/src/main/java/com/arbelkilani/clock/listener/TimeCounterListener.java: -------------------------------------------------------------------------------- 1 | package com.arbelkilani.clock.listener; 2 | 3 | import com.arbelkilani.clock.enumeration.TimeCounterState; 4 | 5 | public interface TimeCounterListener { 6 | 7 | void onTimeCounterCompleted(); 8 | 9 | void onTimeCounterStateChanged(TimeCounterState timeCounterState); 10 | 11 | } 12 | -------------------------------------------------------------------------------- /clock/src/main/java/com/arbelkilani/clock/model/StopwatchSavedItem.java: -------------------------------------------------------------------------------- 1 | package com.arbelkilani.clock.model; 2 | 3 | import java.util.Calendar; 4 | import java.util.Date; 5 | 6 | public class StopwatchSavedItem { 7 | 8 | private int mSeconds; 9 | private int mMinutes; 10 | private Calendar mCalendar; 11 | 12 | public StopwatchSavedItem(Calendar mCalendar, int mSeconds, int mMinutes) { 13 | this.mSeconds = mSeconds; 14 | this.mMinutes = mMinutes; 15 | this.mCalendar = mCalendar; 16 | } 17 | 18 | public int getSeconds() { 19 | return mSeconds; 20 | } 21 | 22 | public void setSeconds(int mSeconds) { 23 | this.mSeconds = mSeconds; 24 | } 25 | 26 | public int getMinutes() { 27 | return mMinutes; 28 | } 29 | 30 | public void setMinutes(int mMinutes) { 31 | this.mMinutes = mMinutes; 32 | } 33 | 34 | public Calendar getCalendar() { 35 | return mCalendar; 36 | } 37 | 38 | public void setCalendar(Calendar mCalendar) { 39 | this.mCalendar = mCalendar; 40 | } 41 | 42 | @Override 43 | public String toString() { 44 | return "StopwatchSavedItem{" + 45 | "mSeconds=" + mSeconds + 46 | ", mMinutes=" + mMinutes + 47 | ", mCalendar=" + mCalendar + 48 | '}'; 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /clock/src/main/java/com/arbelkilani/clock/model/theme/AnalogicalTheme.java: -------------------------------------------------------------------------------- 1 | package com.arbelkilani.clock.model.theme; 2 | 3 | import com.arbelkilani.clock.enumeration.ClockType; 4 | import com.arbelkilani.clock.enumeration.analogical.DegreeType; 5 | import com.arbelkilani.clock.enumeration.analogical.DegreesStep; 6 | import com.arbelkilani.clock.enumeration.analogical.ValueDisposition; 7 | import com.arbelkilani.clock.enumeration.analogical.ValueStep; 8 | import com.arbelkilani.clock.enumeration.analogical.ValueType; 9 | 10 | public class AnalogicalTheme { 11 | 12 | private ClockType clockType; 13 | 14 | private int clockBackground; 15 | 16 | private boolean showCenter; 17 | private int centerInnerColor; 18 | private int centerOuterColor; 19 | 20 | private boolean showBorder; 21 | private int borderColor; 22 | 23 | private boolean showSecondsNeedle; 24 | private int needleHoursColor; 25 | private int needleMinutesColor; 26 | private int needleSecondsColor; 27 | 28 | private boolean showProgress; 29 | private int progressColor; 30 | private boolean showMinutesProgress; 31 | private int minutesProgressColor; 32 | private float minutesProgressFactor; 33 | private boolean showSecondsProgress; 34 | private int secondsProgressColor; 35 | private float secondsProgressFactor; 36 | 37 | private boolean showDegrees; 38 | private int degreesColor; 39 | private DegreeType degreesType; 40 | private DegreesStep degreesStep; 41 | 42 | private int valuesFont; 43 | private int valuesColor; 44 | private boolean showHoursValues; 45 | private boolean showMinutesValues; 46 | private float minutesValuesFactor; 47 | private ValueStep valueStep; 48 | private ValueType valueType; 49 | private ValueDisposition valueDisposition; 50 | 51 | public ClockType getClockType() { 52 | return clockType; 53 | } 54 | 55 | public int getClockBackground() { 56 | return clockBackground; 57 | } 58 | 59 | public boolean isShowCenter() { 60 | return showCenter; 61 | } 62 | 63 | public int getCenterInnerColor() { 64 | return centerInnerColor; 65 | } 66 | 67 | public int getCenterOuterColor() { 68 | return centerOuterColor; 69 | } 70 | 71 | public boolean isShowBorder() { 72 | return showBorder; 73 | } 74 | 75 | public int getBorderColor() { 76 | return borderColor; 77 | } 78 | 79 | public boolean isShowSecondsNeedle() { 80 | return showSecondsNeedle; 81 | } 82 | 83 | public int getNeedleHoursColor() { 84 | return needleHoursColor; 85 | } 86 | 87 | public int getNeedleMinutesColor() { 88 | return needleMinutesColor; 89 | } 90 | 91 | public int getNeedleSecondsColor() { 92 | return needleSecondsColor; 93 | } 94 | 95 | public boolean isShowProgress() { 96 | return showProgress; 97 | } 98 | 99 | public int getProgressColor() { 100 | return progressColor; 101 | } 102 | 103 | public boolean isShowMinutesProgress() { 104 | return showMinutesProgress; 105 | } 106 | 107 | public int getMinutesProgressColor() { 108 | return minutesProgressColor; 109 | } 110 | 111 | public float getMinutesProgressFactor() { 112 | return minutesProgressFactor; 113 | } 114 | 115 | public boolean isShowSecondsProgress() { 116 | return showSecondsProgress; 117 | } 118 | 119 | public int getSecondsProgressColor() { 120 | return secondsProgressColor; 121 | } 122 | 123 | public float getSecondsProgressFactor() { 124 | return secondsProgressFactor; 125 | } 126 | 127 | public boolean isShowDegrees() { 128 | return showDegrees; 129 | } 130 | 131 | public DegreeType getDegreesType() { 132 | return degreesType; 133 | } 134 | 135 | public DegreesStep getDegreesStep() { 136 | return degreesStep; 137 | } 138 | 139 | public int getDegreesColor() { 140 | return degreesColor; 141 | } 142 | 143 | public int getValuesFont() { 144 | return valuesFont; 145 | } 146 | 147 | public int getValuesColor() { 148 | return valuesColor; 149 | } 150 | 151 | public boolean isShowHoursValues() { 152 | return showHoursValues; 153 | } 154 | 155 | public boolean isShowMinutesValues() { 156 | return showMinutesValues; 157 | } 158 | 159 | public float getMinutesValuesFactor() { 160 | return minutesValuesFactor; 161 | } 162 | 163 | public ValueStep getValueStep() { 164 | return valueStep; 165 | } 166 | 167 | public ValueType getValueType() { 168 | return valueType; 169 | } 170 | 171 | public ValueDisposition getValueDisposition() { 172 | return valueDisposition; 173 | } 174 | 175 | private AnalogicalTheme(AnalogicalThemeBuilder analogicalThemeBuilder) { 176 | 177 | this.clockType = analogicalThemeBuilder.clockType; 178 | 179 | this.clockBackground = analogicalThemeBuilder.clockBackground; 180 | 181 | this.showCenter = analogicalThemeBuilder.showCenter; 182 | this.centerInnerColor = analogicalThemeBuilder.centerInnerColor; 183 | this.centerOuterColor = analogicalThemeBuilder.centerOuterColor; 184 | 185 | this.showBorder = analogicalThemeBuilder.showBorder; 186 | this.borderColor = analogicalThemeBuilder.borderColor; 187 | 188 | this.showSecondsNeedle = analogicalThemeBuilder.showSecondsNeedle; 189 | this.needleHoursColor = analogicalThemeBuilder.needleHoursColor; 190 | this.needleMinutesColor = analogicalThemeBuilder.needleMinutesColor; 191 | this.needleSecondsColor = analogicalThemeBuilder.needleSecondsColor; 192 | 193 | this.showProgress = analogicalThemeBuilder.showProgress; 194 | this.progressColor = analogicalThemeBuilder.progressColor; 195 | this.showMinutesProgress = analogicalThemeBuilder.showMinutesProgress; 196 | this.minutesProgressColor = analogicalThemeBuilder.minutesProgressColor; 197 | this.minutesProgressFactor = analogicalThemeBuilder.minutesProgressFactor; 198 | this.showSecondsProgress = analogicalThemeBuilder.showSecondsProgress; 199 | this.secondsProgressColor = analogicalThemeBuilder.secondsProgressColor; 200 | this.secondsProgressFactor = analogicalThemeBuilder.secondsProgressFactor; 201 | 202 | this.showDegrees = analogicalThemeBuilder.showDegrees; 203 | this.degreesColor = analogicalThemeBuilder.degreesColor; 204 | this.degreesType = analogicalThemeBuilder.degreesType; 205 | this.degreesStep = analogicalThemeBuilder.degreesStep; 206 | 207 | this.valuesFont = analogicalThemeBuilder.valuesFont; 208 | this.valuesColor = analogicalThemeBuilder.valuesColor; 209 | this.showHoursValues = analogicalThemeBuilder.showHoursValues; 210 | this.showMinutesValues = analogicalThemeBuilder.showMinutesValues; 211 | this.minutesValuesFactor = analogicalThemeBuilder.minutesValuesFactor; 212 | this.valueStep = analogicalThemeBuilder.valueStep; 213 | this.valueType = analogicalThemeBuilder.valueType; 214 | this.valueDisposition = analogicalThemeBuilder.valueDisposition; 215 | } 216 | 217 | public static class AnalogicalThemeBuilder { 218 | 219 | private ClockType clockType; 220 | 221 | private int clockBackground; 222 | 223 | private boolean showCenter; 224 | private int centerInnerColor; 225 | private int centerOuterColor; 226 | 227 | private boolean showBorder; 228 | private int borderColor; 229 | 230 | private boolean showSecondsNeedle; 231 | private int needleHoursColor; 232 | private int needleMinutesColor; 233 | private int needleSecondsColor; 234 | 235 | private boolean showProgress; 236 | private int progressColor; 237 | private boolean showMinutesProgress; 238 | private int minutesProgressColor; 239 | private float minutesProgressFactor; 240 | private boolean showSecondsProgress; 241 | private int secondsProgressColor; 242 | private float secondsProgressFactor; 243 | 244 | private boolean showDegrees; 245 | private int degreesColor; 246 | private DegreeType degreesType; 247 | private DegreesStep degreesStep; 248 | 249 | private int valuesFont; 250 | private int valuesColor; 251 | private boolean showHoursValues; 252 | private boolean showMinutesValues; 253 | private float minutesValuesFactor; 254 | private ValueStep valueStep; 255 | private ValueType valueType; 256 | private ValueDisposition valueDisposition; 257 | 258 | public AnalogicalThemeBuilder setClockType(ClockType clockType) { 259 | this.clockType = clockType; 260 | return this; 261 | } 262 | 263 | public AnalogicalThemeBuilder setClockBackground(int clockBackground) { 264 | this.clockBackground = clockBackground; 265 | return this; 266 | } 267 | 268 | public AnalogicalThemeBuilder setShowCenter(boolean showCenter) { 269 | this.showCenter = showCenter; 270 | return this; 271 | } 272 | 273 | public AnalogicalThemeBuilder setCenterInnerColor(int centerInnerColor) { 274 | this.centerInnerColor = centerInnerColor; 275 | return this; 276 | } 277 | 278 | public AnalogicalThemeBuilder setCenterOuterColor(int centerOuterColor) { 279 | this.centerOuterColor = centerOuterColor; 280 | return this; 281 | } 282 | 283 | public AnalogicalThemeBuilder setShowBorder(boolean showBorder) { 284 | this.showBorder = showBorder; 285 | return this; 286 | } 287 | 288 | public AnalogicalThemeBuilder setBorderColor(int borderColor) { 289 | this.borderColor = borderColor; 290 | return this; 291 | } 292 | 293 | public AnalogicalThemeBuilder setShowSecondsNeedle(boolean showSecondsNeedle) { 294 | this.showSecondsNeedle = showSecondsNeedle; 295 | return this; 296 | } 297 | 298 | public AnalogicalThemeBuilder setNeedleHoursColor(int needleHoursColor) { 299 | this.needleHoursColor = needleHoursColor; 300 | return this; 301 | } 302 | 303 | public AnalogicalThemeBuilder setNeedleMinutesColor(int needleMinutesColor) { 304 | this.needleMinutesColor = needleMinutesColor; 305 | return this; 306 | } 307 | 308 | public AnalogicalThemeBuilder setNeedleSecondsColor(int needleSecondsColor) { 309 | this.needleSecondsColor = needleSecondsColor; 310 | return this; 311 | } 312 | 313 | public AnalogicalThemeBuilder setShowProgress(boolean showProgress) { 314 | this.showProgress = showProgress; 315 | return this; 316 | } 317 | 318 | public AnalogicalThemeBuilder setProgressColor(int progressColor) { 319 | this.progressColor = progressColor; 320 | return this; 321 | } 322 | 323 | public AnalogicalThemeBuilder setShowMinutesProgress(boolean showMinutesProgress) { 324 | this.showMinutesProgress = showMinutesProgress; 325 | return this; 326 | } 327 | 328 | public AnalogicalThemeBuilder setMinutesProgressColor(int minutesProgressColor) { 329 | this.minutesProgressColor = minutesProgressColor; 330 | return this; 331 | } 332 | 333 | public AnalogicalThemeBuilder setMinutesProgressFactor(float minutesProgressFactor) { 334 | this.minutesProgressFactor = minutesProgressFactor; 335 | return this; 336 | } 337 | 338 | public AnalogicalThemeBuilder setShowSecondsProgress(boolean showSecondsProgress) { 339 | this.showSecondsProgress = showSecondsProgress; 340 | return this; 341 | } 342 | 343 | public AnalogicalThemeBuilder setSecondsProgressColor(int secondsProgressColor) { 344 | this.secondsProgressColor = secondsProgressColor; 345 | return this; 346 | } 347 | 348 | public AnalogicalThemeBuilder setSecondsProgressFactor(float secondsProgressFactor) { 349 | this.secondsProgressFactor = secondsProgressFactor; 350 | return this; 351 | } 352 | 353 | public AnalogicalThemeBuilder setShowDegrees(boolean showDegrees) { 354 | this.showDegrees = showDegrees; 355 | return this; 356 | } 357 | 358 | public AnalogicalThemeBuilder setClockDegreesType(DegreeType degreesType) { 359 | this.degreesType = degreesType; 360 | return this; 361 | } 362 | 363 | public AnalogicalThemeBuilder setDegreesStep(DegreesStep degreesStep) { 364 | this.degreesStep = degreesStep; 365 | return this; 366 | } 367 | 368 | public AnalogicalThemeBuilder setDegreesColor(int degreesColor) { 369 | this.degreesColor = degreesColor; 370 | return this; 371 | } 372 | 373 | public AnalogicalThemeBuilder setDegreesType(DegreeType degreesType) { 374 | this.degreesType = degreesType; 375 | return this; 376 | } 377 | 378 | public AnalogicalThemeBuilder setValuesFont(int valuesFont) { 379 | this.valuesFont = valuesFont; 380 | return this; 381 | } 382 | 383 | public AnalogicalThemeBuilder setValuesColor(int valuesColor) { 384 | this.valuesColor = valuesColor; 385 | return this; 386 | } 387 | 388 | public AnalogicalThemeBuilder setShowHoursValues(boolean showHoursValues) { 389 | this.showHoursValues = showHoursValues; 390 | return this; 391 | } 392 | 393 | public AnalogicalThemeBuilder setShowMinutesValues(boolean showMinutesValues) { 394 | this.showMinutesValues = showMinutesValues; 395 | return this; 396 | } 397 | 398 | public AnalogicalThemeBuilder setMinutesValuesFactor(float minutesValuesFactor) { 399 | this.minutesValuesFactor = minutesValuesFactor; 400 | return this; 401 | } 402 | 403 | public AnalogicalThemeBuilder setValueStep(ValueStep valueStep) { 404 | this.valueStep = valueStep; 405 | return this; 406 | } 407 | 408 | public AnalogicalThemeBuilder setValueType(ValueType valueType) { 409 | this.valueType = valueType; 410 | return this; 411 | } 412 | 413 | public AnalogicalThemeBuilder setValueDisposition(ValueDisposition valueDisposition) { 414 | this.valueDisposition = valueDisposition; 415 | return this; 416 | } 417 | 418 | public AnalogicalTheme build() { 419 | return new AnalogicalTheme(this); 420 | } 421 | } 422 | } 423 | -------------------------------------------------------------------------------- /clock/src/main/java/com/arbelkilani/clock/model/theme/NumericTheme.java: -------------------------------------------------------------------------------- 1 | package com.arbelkilani.clock.model.theme; 2 | 3 | import com.arbelkilani.clock.enumeration.BorderStyle; 4 | import com.arbelkilani.clock.enumeration.ClockType; 5 | import com.arbelkilani.clock.enumeration.numeric.NumericFormat; 6 | 7 | public class NumericTheme { 8 | 9 | private ClockType clockType; 10 | 11 | private int clockBackground; 12 | 13 | private int valuesFont; 14 | private int valuesColor; 15 | 16 | private boolean showBorder; 17 | private int borderColor; 18 | private BorderStyle borderStyle; 19 | private int borderRadiusRx; 20 | private int borderRadiusRy; 21 | 22 | private NumericFormat numericFormat; 23 | 24 | private boolean numericShowSeconds; 25 | 26 | public ClockType getClockType() { 27 | return clockType; 28 | } 29 | 30 | public int getClockBackground() { 31 | return clockBackground; 32 | } 33 | 34 | public int getValuesFont() { 35 | return valuesFont; 36 | } 37 | 38 | public int getValuesColor() { 39 | return valuesColor; 40 | } 41 | 42 | public boolean isShowBorder() { 43 | return showBorder; 44 | } 45 | 46 | public int getBorderColor() { 47 | return borderColor; 48 | } 49 | 50 | public BorderStyle getBorderStyle() { 51 | return borderStyle; 52 | } 53 | 54 | public int getBorderRadiusRx() { 55 | return borderRadiusRx; 56 | } 57 | 58 | public int getBorderRadiusRy() { 59 | return borderRadiusRy; 60 | } 61 | 62 | public NumericFormat getNumericFormat() { 63 | return numericFormat; 64 | } 65 | 66 | public boolean isNumericShowSeconds() { 67 | return numericShowSeconds; 68 | } 69 | 70 | private NumericTheme(NumericThemeBuilder numericThemeBuilder) { 71 | 72 | this.clockType = numericThemeBuilder.clockType; 73 | 74 | this.clockBackground = numericThemeBuilder.clockBackground; 75 | 76 | this.valuesFont = numericThemeBuilder.valuesFont; 77 | this.valuesColor = numericThemeBuilder.valuesColor; 78 | 79 | this.showBorder = numericThemeBuilder.showBorder; 80 | this.borderColor = numericThemeBuilder.borderColor; 81 | this.borderStyle = numericThemeBuilder.borderStyle; 82 | this.borderRadiusRx = numericThemeBuilder.borderRadiusRx; 83 | this.borderRadiusRy = numericThemeBuilder.borderRadiusRy; 84 | 85 | this.numericFormat = numericThemeBuilder.numericFormat; 86 | 87 | this.numericShowSeconds = numericThemeBuilder.numericShowSeconds; 88 | } 89 | 90 | public static class NumericThemeBuilder { 91 | 92 | private ClockType clockType; 93 | 94 | private int clockBackground; 95 | 96 | private int valuesFont; 97 | private int valuesColor; 98 | 99 | private boolean showBorder; 100 | private int borderColor; 101 | private BorderStyle borderStyle; 102 | private int borderRadiusRx; 103 | private int borderRadiusRy; 104 | 105 | private NumericFormat numericFormat; 106 | 107 | private boolean numericShowSeconds; 108 | 109 | public NumericThemeBuilder setClockType(ClockType clockType) { 110 | this.clockType = clockType; 111 | return this; 112 | } 113 | 114 | public NumericThemeBuilder setClockBackground(int clockBackground) { 115 | this.clockBackground = clockBackground; 116 | return this; 117 | } 118 | 119 | public NumericThemeBuilder setValuesFont(int valuesFont) { 120 | this.valuesFont = valuesFont; 121 | return this; 122 | } 123 | 124 | public NumericThemeBuilder setValuesColor(int valuesColor) { 125 | this.valuesColor = valuesColor; 126 | return this; 127 | } 128 | 129 | public NumericThemeBuilder setShowBorder(boolean showBorder) { 130 | this.showBorder = showBorder; 131 | return this; 132 | } 133 | 134 | public NumericThemeBuilder setBorderColor(int borderColor) { 135 | this.borderColor = borderColor; 136 | return this; 137 | } 138 | 139 | public NumericThemeBuilder setBorderStyle(BorderStyle borderStyle) { 140 | this.borderStyle = borderStyle; 141 | return this; 142 | } 143 | 144 | public NumericThemeBuilder setBorderRadius(int borderRadiusRx, int borderRadiusRy) { 145 | this.borderRadiusRx = borderRadiusRx; 146 | this.borderRadiusRy = borderRadiusRy; 147 | return this; 148 | } 149 | 150 | public NumericThemeBuilder setNumericFormat(NumericFormat numericFormat) { 151 | this.numericFormat = numericFormat; 152 | return this; 153 | } 154 | 155 | public NumericThemeBuilder setNumericShowSeconds(boolean numericShowSeconds) { 156 | this.numericShowSeconds = numericShowSeconds; 157 | return this; 158 | } 159 | 160 | public NumericTheme build() { 161 | return new NumericTheme(this); 162 | } 163 | } 164 | } 165 | -------------------------------------------------------------------------------- /clock/src/main/java/com/arbelkilani/clock/model/theme/StopwatchTheme.java: -------------------------------------------------------------------------------- 1 | package com.arbelkilani.clock.model.theme; 2 | 3 | import com.arbelkilani.clock.enumeration.BorderStyle; 4 | import com.arbelkilani.clock.enumeration.ClockType; 5 | 6 | public class StopwatchTheme { 7 | 8 | private ClockType clockType; 9 | 10 | private int clockBackground; 11 | 12 | private int valuesFont; 13 | private int valuesColor; 14 | 15 | private boolean showBorder; 16 | private int borderColor; 17 | private BorderStyle borderStyle; 18 | private int borderRadiusRx; 19 | private int borderRadiusRy; 20 | 21 | public ClockType getClockType() { 22 | return clockType; 23 | } 24 | 25 | public int getClockBackground() { 26 | return clockBackground; 27 | } 28 | 29 | public int getValuesFont() { 30 | return valuesFont; 31 | } 32 | 33 | public int getValuesColor() { 34 | return valuesColor; 35 | } 36 | 37 | public boolean isShowBorder() { 38 | return showBorder; 39 | } 40 | 41 | public int getBorderColor() { 42 | return borderColor; 43 | } 44 | 45 | public BorderStyle getBorderStyle() { 46 | return borderStyle; 47 | } 48 | 49 | public int getBorderRadiusRx() { 50 | return borderRadiusRx; 51 | } 52 | 53 | public int getBorderRadiusRy() { 54 | return borderRadiusRy; 55 | } 56 | 57 | private StopwatchTheme(StopwatchThemeBuilder stopwatchThemeBuilder) { 58 | 59 | this.clockType = stopwatchThemeBuilder.clockType; 60 | 61 | this.clockBackground = stopwatchThemeBuilder.clockBackground; 62 | 63 | this.valuesFont = stopwatchThemeBuilder.valuesFont; 64 | this.valuesColor = stopwatchThemeBuilder.valuesColor; 65 | 66 | this.showBorder = stopwatchThemeBuilder.showBorder; 67 | this.borderColor = stopwatchThemeBuilder.borderColor; 68 | this.borderStyle = stopwatchThemeBuilder.borderStyle; 69 | this.borderRadiusRx = stopwatchThemeBuilder.borderRadiusRx; 70 | this.borderRadiusRy = stopwatchThemeBuilder.borderRadiusRy; 71 | } 72 | 73 | public static class StopwatchThemeBuilder { 74 | 75 | private ClockType clockType; 76 | 77 | private int clockBackground; 78 | 79 | private int valuesFont; 80 | private int valuesColor; 81 | 82 | private boolean showBorder; 83 | private int borderColor; 84 | private BorderStyle borderStyle; 85 | private int borderRadiusRx; 86 | private int borderRadiusRy; 87 | 88 | public StopwatchThemeBuilder setClockType(ClockType clockType) { 89 | this.clockType = clockType; 90 | return this; 91 | } 92 | 93 | public StopwatchThemeBuilder setClockBackground(int clockBackground) { 94 | this.clockBackground = clockBackground; 95 | return this; 96 | } 97 | 98 | public StopwatchThemeBuilder setValuesFont(int valuesFont) { 99 | this.valuesFont = valuesFont; 100 | return this; 101 | } 102 | 103 | public StopwatchThemeBuilder setValuesColor(int valuesColor) { 104 | this.valuesColor = valuesColor; 105 | return this; 106 | } 107 | 108 | public StopwatchThemeBuilder setShowBorder(boolean showBorder) { 109 | this.showBorder = showBorder; 110 | return this; 111 | } 112 | 113 | public StopwatchThemeBuilder setBorderColor(int borderColor) { 114 | this.borderColor = borderColor; 115 | return this; 116 | } 117 | 118 | public StopwatchThemeBuilder setBorderStyle(BorderStyle borderStyle) { 119 | this.borderStyle = borderStyle; 120 | return this; 121 | } 122 | 123 | public StopwatchThemeBuilder setBorderRadiusRx(int borderRadiusRx) { 124 | this.borderRadiusRx = borderRadiusRx; 125 | return this; 126 | } 127 | 128 | public StopwatchThemeBuilder setBorderRadiusRy(int borderRadiusRy) { 129 | this.borderRadiusRy = borderRadiusRy; 130 | return this; 131 | } 132 | 133 | public StopwatchTheme build() { 134 | return new StopwatchTheme(this); 135 | } 136 | } 137 | } 138 | -------------------------------------------------------------------------------- /clock/src/main/java/com/arbelkilani/clock/model/theme/TimeCounterTheme.java: -------------------------------------------------------------------------------- 1 | package com.arbelkilani.clock.model.theme; 2 | 3 | import com.arbelkilani.clock.enumeration.ClockType; 4 | 5 | public class TimeCounterTheme { 6 | 7 | private ClockType clockType; 8 | 9 | private int clockBackground; 10 | 11 | private int valuesFont; 12 | private int valuesColor; 13 | 14 | private boolean showProgress; 15 | private int progressColor; 16 | private int borderColor; 17 | 18 | public ClockType getClockType() { 19 | return clockType; 20 | } 21 | 22 | public int getClockBackground() { 23 | return clockBackground; 24 | } 25 | 26 | public int getValuesFont() { 27 | return valuesFont; 28 | } 29 | 30 | public int getValuesColor() { 31 | return valuesColor; 32 | } 33 | 34 | public boolean isShowProgress() { 35 | return showProgress; 36 | } 37 | 38 | public int getProgressColor() { 39 | return progressColor; 40 | } 41 | 42 | public int getBorderColor() { 43 | return borderColor; 44 | } 45 | 46 | private TimeCounterTheme(TimeCounterThemeBuilder timeCounterThemeBuilder) { 47 | 48 | this.clockType = timeCounterThemeBuilder.clockType; 49 | 50 | this.clockBackground = timeCounterThemeBuilder.clockBackground; 51 | 52 | this.valuesFont = timeCounterThemeBuilder.valuesFont; 53 | this.valuesColor = timeCounterThemeBuilder.valuesColor; 54 | 55 | this.showProgress = timeCounterThemeBuilder.showProgress; 56 | this.progressColor = timeCounterThemeBuilder.progressColor; 57 | this.borderColor = timeCounterThemeBuilder.borderColor; 58 | } 59 | 60 | public static class TimeCounterThemeBuilder { 61 | 62 | private ClockType clockType; 63 | 64 | private int clockBackground; 65 | 66 | private int valuesFont; 67 | private int valuesColor; 68 | 69 | private boolean showProgress; 70 | private int progressColor; 71 | private int borderColor; 72 | 73 | public TimeCounterThemeBuilder setClockType(ClockType clockType) { 74 | this.clockType = clockType; 75 | return this; 76 | } 77 | 78 | public TimeCounterThemeBuilder setClockBackground(int clockBackground) { 79 | this.clockBackground = clockBackground; 80 | return this; 81 | } 82 | 83 | public TimeCounterThemeBuilder setValuesFont(int valuesFont) { 84 | this.valuesFont = valuesFont; 85 | return this; 86 | } 87 | 88 | public TimeCounterThemeBuilder setValuesColor(int valuesColor) { 89 | this.valuesColor = valuesColor; 90 | return this; 91 | } 92 | 93 | public TimeCounterThemeBuilder setShowProgress(boolean showProgress) { 94 | this.showProgress = showProgress; 95 | return this; 96 | } 97 | 98 | public TimeCounterThemeBuilder setProgressColor(int progressColor) { 99 | this.progressColor = progressColor; 100 | return this; 101 | } 102 | 103 | public TimeCounterThemeBuilder setBorderColor(int borderColor) { 104 | this.borderColor = borderColor; 105 | return this; 106 | } 107 | 108 | public TimeCounterTheme build() { 109 | return new TimeCounterTheme(this); 110 | } 111 | } 112 | } 113 | -------------------------------------------------------------------------------- /clock/src/main/java/com/arbelkilani/clock/runnable/ClockRunnable.java: -------------------------------------------------------------------------------- 1 | package com.arbelkilani.clock.runnable; 2 | 3 | import android.view.View; 4 | 5 | public class ClockRunnable implements Runnable { 6 | 7 | private static final long SECOND = 1000; 8 | private View mView; 9 | 10 | public ClockRunnable(View view) { 11 | mView = view; 12 | } 13 | 14 | @Override 15 | public void run() { 16 | mView.invalidate(); 17 | mView.postDelayed(this, SECOND); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /clock/src/main/java/com/arbelkilani/clock/runnable/StopWatchRunnable.java: -------------------------------------------------------------------------------- 1 | package com.arbelkilani.clock.runnable; 2 | 3 | import android.view.View; 4 | 5 | public class StopWatchRunnable implements Runnable { 6 | 7 | private View mView; 8 | 9 | public StopWatchRunnable(View view) { 10 | mView = view; 11 | } 12 | 13 | @Override 14 | public void run() { 15 | mView.invalidate(); 16 | mView.postDelayed(this, 0); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /clock/src/main/java/com/arbelkilani/clock/runnable/TimeCounterRunnable.java: -------------------------------------------------------------------------------- 1 | package com.arbelkilani.clock.runnable; 2 | 3 | import android.view.View; 4 | 5 | public class TimeCounterRunnable implements Runnable { 6 | 7 | private View mView; 8 | 9 | public TimeCounterRunnable(View view) { 10 | mView = view; 11 | } 12 | 13 | @Override 14 | public void run() { 15 | mView.invalidate(); 16 | mView.postDelayed(this, 1000); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /clock/src/main/res/font/proxima_nova_regular.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arbelkilani/Clock-view/6ccea2253b76a65db03fcff1353b551a3d9ed0e6/clock/src/main/res/font/proxima_nova_regular.otf -------------------------------------------------------------------------------- /clock/src/main/res/font/proxima_nova_thin.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arbelkilani/Clock-view/6ccea2253b76a65db03fcff1353b551a3d9ed0e6/clock/src/main/res/font/proxima_nova_thin.otf -------------------------------------------------------------------------------- /clock/src/main/res/values/attrs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | -------------------------------------------------------------------------------- /clock/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | Clock 3 | 4 | -------------------------------------------------------------------------------- /clock/src/test/java/com/arbelkilani/clock/ExampleUnitTest.java: -------------------------------------------------------------------------------- 1 | package com.arbelkilani.clock; 2 | 3 | import org.junit.Test; 4 | 5 | import static org.junit.Assert.*; 6 | 7 | /** 8 | * Example local unit test, which will execute on the development machine (host). 9 | * 10 | * @see Testing documentation 11 | */ 12 | public class ExampleUnitTest { 13 | @Test 14 | public void addition_isCorrect() { 15 | assertEquals(4, 2 + 2); 16 | } 17 | } -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | # Project-wide Gradle settings. 2 | # IDE (e.g. Android Studio) users: 3 | # Gradle settings configured through the IDE *will override* 4 | # any settings specified in this file. 5 | # For more details on how to configure your build environment visit 6 | # http://www.gradle.org/docs/current/userguide/build_environment.html 7 | # Specifies the JVM arguments used for the daemon process. 8 | # The setting is particularly useful for tweaking memory settings. 9 | android.enableJetifier=true 10 | android.useAndroidX=true 11 | org.gradle.jvmargs=-Xmx1536m 12 | # When configured, Gradle will run in incubating parallel mode. 13 | # This option should only be used with decoupled projects. More details, visit 14 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects 15 | # org.gradle.parallel=true 16 | 17 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arbelkilani/Clock-view/6ccea2253b76a65db03fcff1353b551a3d9ed0e6/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Mon Jan 06 03:31:26 CET 2020 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-5.4.1-all.zip 7 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | ############################################################################## 4 | ## 5 | ## Gradle start up script for UN*X 6 | ## 7 | ############################################################################## 8 | 9 | # Attempt to set APP_HOME 10 | # Resolve links: $0 may be a link 11 | PRG="$0" 12 | # Need this for relative symlinks. 13 | while [ -h "$PRG" ] ; do 14 | ls=`ls -ld "$PRG"` 15 | link=`expr "$ls" : '.*-> \(.*\)$'` 16 | if expr "$link" : '/.*' > /dev/null; then 17 | PRG="$link" 18 | else 19 | PRG=`dirname "$PRG"`"/$link" 20 | fi 21 | done 22 | SAVED="`pwd`" 23 | cd "`dirname \"$PRG\"`/" >/dev/null 24 | APP_HOME="`pwd -P`" 25 | cd "$SAVED" >/dev/null 26 | 27 | APP_NAME="Gradle" 28 | APP_BASE_NAME=`basename "$0"` 29 | 30 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 31 | DEFAULT_JVM_OPTS="" 32 | 33 | # Use the maximum available, or set MAX_FD != -1 to use that value. 34 | MAX_FD="maximum" 35 | 36 | warn () { 37 | echo "$*" 38 | } 39 | 40 | die () { 41 | echo 42 | echo "$*" 43 | echo 44 | exit 1 45 | } 46 | 47 | # OS specific support (must be 'true' or 'false'). 48 | cygwin=false 49 | msys=false 50 | darwin=false 51 | nonstop=false 52 | case "`uname`" in 53 | CYGWIN* ) 54 | cygwin=true 55 | ;; 56 | Darwin* ) 57 | darwin=true 58 | ;; 59 | MINGW* ) 60 | msys=true 61 | ;; 62 | NONSTOP* ) 63 | nonstop=true 64 | ;; 65 | esac 66 | 67 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 68 | 69 | # Determine the Java command to use to start the JVM. 70 | if [ -n "$JAVA_HOME" ] ; then 71 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 72 | # IBM's JDK on AIX uses strange locations for the executables 73 | JAVACMD="$JAVA_HOME/jre/sh/java" 74 | else 75 | JAVACMD="$JAVA_HOME/bin/java" 76 | fi 77 | if [ ! -x "$JAVACMD" ] ; then 78 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 79 | 80 | Please set the JAVA_HOME variable in your environment to match the 81 | location of your Java installation." 82 | fi 83 | else 84 | JAVACMD="java" 85 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 86 | 87 | Please set the JAVA_HOME variable in your environment to match the 88 | location of your Java installation." 89 | fi 90 | 91 | # Increase the maximum file descriptors if we can. 92 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then 93 | MAX_FD_LIMIT=`ulimit -H -n` 94 | if [ $? -eq 0 ] ; then 95 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 96 | MAX_FD="$MAX_FD_LIMIT" 97 | fi 98 | ulimit -n $MAX_FD 99 | if [ $? -ne 0 ] ; then 100 | warn "Could not set maximum file descriptor limit: $MAX_FD" 101 | fi 102 | else 103 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 104 | fi 105 | fi 106 | 107 | # For Darwin, add options to specify how the application appears in the dock 108 | if $darwin; then 109 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 110 | fi 111 | 112 | # For Cygwin, switch paths to Windows format before running java 113 | if $cygwin ; then 114 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 115 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 116 | JAVACMD=`cygpath --unix "$JAVACMD"` 117 | 118 | # We build the pattern for arguments to be converted via cygpath 119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 120 | SEP="" 121 | for dir in $ROOTDIRSRAW ; do 122 | ROOTDIRS="$ROOTDIRS$SEP$dir" 123 | SEP="|" 124 | done 125 | OURCYGPATTERN="(^($ROOTDIRS))" 126 | # Add a user-defined pattern to the cygpath arguments 127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 129 | fi 130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 131 | i=0 132 | for arg in "$@" ; do 133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 135 | 136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 138 | else 139 | eval `echo args$i`="\"$arg\"" 140 | fi 141 | i=$((i+1)) 142 | done 143 | case $i in 144 | (0) set -- ;; 145 | (1) set -- "$args0" ;; 146 | (2) set -- "$args0" "$args1" ;; 147 | (3) set -- "$args0" "$args1" "$args2" ;; 148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 154 | esac 155 | fi 156 | 157 | # Escape application args 158 | save () { 159 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done 160 | echo " " 161 | } 162 | APP_ARGS=$(save "$@") 163 | 164 | # Collect all arguments for the java command, following the shell quoting and substitution rules 165 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" 166 | 167 | # by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong 168 | if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then 169 | cd "$(dirname "$0")" 170 | fi 171 | 172 | exec "$JAVACMD" "$@" 173 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | set DIRNAME=%~dp0 12 | if "%DIRNAME%" == "" set DIRNAME=. 13 | set APP_BASE_NAME=%~n0 14 | set APP_HOME=%DIRNAME% 15 | 16 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 17 | set DEFAULT_JVM_OPTS= 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windows variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | 53 | :win9xME_args 54 | @rem Slurp the command line arguments. 55 | set CMD_LINE_ARGS= 56 | set _SKIP=2 57 | 58 | :win9xME_args_slurp 59 | if "x%~1" == "x" goto execute 60 | 61 | set CMD_LINE_ARGS=%* 62 | 63 | :execute 64 | @rem Setup the command line 65 | 66 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 67 | 68 | @rem Execute Gradle 69 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 70 | 71 | :end 72 | @rem End local scope for the variables with windows NT shell 73 | if "%ERRORLEVEL%"=="0" goto mainEnd 74 | 75 | :fail 76 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 77 | rem the _cmd.exe /c_ return code! 78 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 79 | exit /b 1 80 | 81 | :mainEnd 82 | if "%OS%"=="Windows_NT" endlocal 83 | 84 | :omega 85 | -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | include ':app', ':clock' 2 | -------------------------------------------------------------------------------- /wiki/analogical/bg/1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arbelkilani/Clock-view/6ccea2253b76a65db03fcff1353b551a3d9ed0e6/wiki/analogical/bg/1.png -------------------------------------------------------------------------------- /wiki/analogical/bg/2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arbelkilani/Clock-view/6ccea2253b76a65db03fcff1353b551a3d9ed0e6/wiki/analogical/bg/2.png -------------------------------------------------------------------------------- /wiki/analogical/bg/3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arbelkilani/Clock-view/6ccea2253b76a65db03fcff1353b551a3d9ed0e6/wiki/analogical/bg/3.png -------------------------------------------------------------------------------- /wiki/analogical/border/1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arbelkilani/Clock-view/6ccea2253b76a65db03fcff1353b551a3d9ed0e6/wiki/analogical/border/1.png -------------------------------------------------------------------------------- /wiki/analogical/border/2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arbelkilani/Clock-view/6ccea2253b76a65db03fcff1353b551a3d9ed0e6/wiki/analogical/border/2.png -------------------------------------------------------------------------------- /wiki/analogical/border/3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arbelkilani/Clock-view/6ccea2253b76a65db03fcff1353b551a3d9ed0e6/wiki/analogical/border/3.png -------------------------------------------------------------------------------- /wiki/analogical/center/1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arbelkilani/Clock-view/6ccea2253b76a65db03fcff1353b551a3d9ed0e6/wiki/analogical/center/1.png -------------------------------------------------------------------------------- /wiki/analogical/center/2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arbelkilani/Clock-view/6ccea2253b76a65db03fcff1353b551a3d9ed0e6/wiki/analogical/center/2.png -------------------------------------------------------------------------------- /wiki/analogical/center/3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arbelkilani/Clock-view/6ccea2253b76a65db03fcff1353b551a3d9ed0e6/wiki/analogical/center/3.png -------------------------------------------------------------------------------- /wiki/analogical/degree/1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arbelkilani/Clock-view/6ccea2253b76a65db03fcff1353b551a3d9ed0e6/wiki/analogical/degree/1.png -------------------------------------------------------------------------------- /wiki/analogical/degree/2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arbelkilani/Clock-view/6ccea2253b76a65db03fcff1353b551a3d9ed0e6/wiki/analogical/degree/2.png -------------------------------------------------------------------------------- /wiki/analogical/degree/3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arbelkilani/Clock-view/6ccea2253b76a65db03fcff1353b551a3d9ed0e6/wiki/analogical/degree/3.png -------------------------------------------------------------------------------- /wiki/analogical/needle/1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arbelkilani/Clock-view/6ccea2253b76a65db03fcff1353b551a3d9ed0e6/wiki/analogical/needle/1.png -------------------------------------------------------------------------------- /wiki/analogical/needle/2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arbelkilani/Clock-view/6ccea2253b76a65db03fcff1353b551a3d9ed0e6/wiki/analogical/needle/2.png -------------------------------------------------------------------------------- /wiki/analogical/needle/3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arbelkilani/Clock-view/6ccea2253b76a65db03fcff1353b551a3d9ed0e6/wiki/analogical/needle/3.png -------------------------------------------------------------------------------- /wiki/analogical/progress/1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arbelkilani/Clock-view/6ccea2253b76a65db03fcff1353b551a3d9ed0e6/wiki/analogical/progress/1.png -------------------------------------------------------------------------------- /wiki/analogical/progress/2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arbelkilani/Clock-view/6ccea2253b76a65db03fcff1353b551a3d9ed0e6/wiki/analogical/progress/2.png -------------------------------------------------------------------------------- /wiki/analogical/progress/3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arbelkilani/Clock-view/6ccea2253b76a65db03fcff1353b551a3d9ed0e6/wiki/analogical/progress/3.png -------------------------------------------------------------------------------- /wiki/analogical/values/1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arbelkilani/Clock-view/6ccea2253b76a65db03fcff1353b551a3d9ed0e6/wiki/analogical/values/1.png -------------------------------------------------------------------------------- /wiki/analogical/values/2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arbelkilani/Clock-view/6ccea2253b76a65db03fcff1353b551a3d9ed0e6/wiki/analogical/values/2.png -------------------------------------------------------------------------------- /wiki/analogical/values/3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arbelkilani/Clock-view/6ccea2253b76a65db03fcff1353b551a3d9ed0e6/wiki/analogical/values/3.png -------------------------------------------------------------------------------- /wiki/clock_cover.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arbelkilani/Clock-view/6ccea2253b76a65db03fcff1353b551a3d9ed0e6/wiki/clock_cover.png -------------------------------------------------------------------------------- /wiki/clock_screen.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arbelkilani/Clock-view/6ccea2253b76a65db03fcff1353b551a3d9ed0e6/wiki/clock_screen.png -------------------------------------------------------------------------------- /wiki/numeric/border/1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arbelkilani/Clock-view/6ccea2253b76a65db03fcff1353b551a3d9ed0e6/wiki/numeric/border/1.png -------------------------------------------------------------------------------- /wiki/numeric/border/2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arbelkilani/Clock-view/6ccea2253b76a65db03fcff1353b551a3d9ed0e6/wiki/numeric/border/2.png -------------------------------------------------------------------------------- /wiki/numeric/border/3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arbelkilani/Clock-view/6ccea2253b76a65db03fcff1353b551a3d9ed0e6/wiki/numeric/border/3.png -------------------------------------------------------------------------------- /wiki/numeric/color/1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arbelkilani/Clock-view/6ccea2253b76a65db03fcff1353b551a3d9ed0e6/wiki/numeric/color/1.png -------------------------------------------------------------------------------- /wiki/numeric/color/2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arbelkilani/Clock-view/6ccea2253b76a65db03fcff1353b551a3d9ed0e6/wiki/numeric/color/2.png -------------------------------------------------------------------------------- /wiki/numeric/color/3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arbelkilani/Clock-view/6ccea2253b76a65db03fcff1353b551a3d9ed0e6/wiki/numeric/color/3.png -------------------------------------------------------------------------------- /wiki/numeric/font/1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arbelkilani/Clock-view/6ccea2253b76a65db03fcff1353b551a3d9ed0e6/wiki/numeric/font/1.png -------------------------------------------------------------------------------- /wiki/numeric/font/2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arbelkilani/Clock-view/6ccea2253b76a65db03fcff1353b551a3d9ed0e6/wiki/numeric/font/2.png -------------------------------------------------------------------------------- /wiki/numeric/format/1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arbelkilani/Clock-view/6ccea2253b76a65db03fcff1353b551a3d9ed0e6/wiki/numeric/format/1.png -------------------------------------------------------------------------------- /wiki/numeric/format/2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arbelkilani/Clock-view/6ccea2253b76a65db03fcff1353b551a3d9ed0e6/wiki/numeric/format/2.png -------------------------------------------------------------------------------- /wiki/numeric/seconds/1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arbelkilani/Clock-view/6ccea2253b76a65db03fcff1353b551a3d9ed0e6/wiki/numeric/seconds/1.png -------------------------------------------------------------------------------- /wiki/numeric/seconds/2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arbelkilani/Clock-view/6ccea2253b76a65db03fcff1353b551a3d9ed0e6/wiki/numeric/seconds/2.png -------------------------------------------------------------------------------- /wiki/stopwatch/1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arbelkilani/Clock-view/6ccea2253b76a65db03fcff1353b551a3d9ed0e6/wiki/stopwatch/1.png -------------------------------------------------------------------------------- /wiki/stopwatch/2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arbelkilani/Clock-view/6ccea2253b76a65db03fcff1353b551a3d9ed0e6/wiki/stopwatch/2.png -------------------------------------------------------------------------------- /wiki/stopwatch/3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arbelkilani/Clock-view/6ccea2253b76a65db03fcff1353b551a3d9ed0e6/wiki/stopwatch/3.png -------------------------------------------------------------------------------- /wiki/stopwatch/background/1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arbelkilani/Clock-view/6ccea2253b76a65db03fcff1353b551a3d9ed0e6/wiki/stopwatch/background/1.png -------------------------------------------------------------------------------- /wiki/stopwatch/background/2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arbelkilani/Clock-view/6ccea2253b76a65db03fcff1353b551a3d9ed0e6/wiki/stopwatch/background/2.png -------------------------------------------------------------------------------- /wiki/stopwatch/background/3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arbelkilani/Clock-view/6ccea2253b76a65db03fcff1353b551a3d9ed0e6/wiki/stopwatch/background/3.png -------------------------------------------------------------------------------- /wiki/stopwatch/border/1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arbelkilani/Clock-view/6ccea2253b76a65db03fcff1353b551a3d9ed0e6/wiki/stopwatch/border/1.png -------------------------------------------------------------------------------- /wiki/stopwatch/border/2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arbelkilani/Clock-view/6ccea2253b76a65db03fcff1353b551a3d9ed0e6/wiki/stopwatch/border/2.png -------------------------------------------------------------------------------- /wiki/stopwatch/border/3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arbelkilani/Clock-view/6ccea2253b76a65db03fcff1353b551a3d9ed0e6/wiki/stopwatch/border/3.png -------------------------------------------------------------------------------- /wiki/stopwatch/color/1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arbelkilani/Clock-view/6ccea2253b76a65db03fcff1353b551a3d9ed0e6/wiki/stopwatch/color/1.png -------------------------------------------------------------------------------- /wiki/stopwatch/font/1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arbelkilani/Clock-view/6ccea2253b76a65db03fcff1353b551a3d9ed0e6/wiki/stopwatch/font/1.png -------------------------------------------------------------------------------- /wiki/stopwatch_screen.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arbelkilani/Clock-view/6ccea2253b76a65db03fcff1353b551a3d9ed0e6/wiki/stopwatch_screen.png -------------------------------------------------------------------------------- /wiki/time_counter/1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arbelkilani/Clock-view/6ccea2253b76a65db03fcff1353b551a3d9ed0e6/wiki/time_counter/1.png -------------------------------------------------------------------------------- /wiki/time_counter/2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arbelkilani/Clock-view/6ccea2253b76a65db03fcff1353b551a3d9ed0e6/wiki/time_counter/2.png -------------------------------------------------------------------------------- /wiki/time_counter/3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arbelkilani/Clock-view/6ccea2253b76a65db03fcff1353b551a3d9ed0e6/wiki/time_counter/3.png -------------------------------------------------------------------------------- /wiki/time_counter/background/1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arbelkilani/Clock-view/6ccea2253b76a65db03fcff1353b551a3d9ed0e6/wiki/time_counter/background/1.png -------------------------------------------------------------------------------- /wiki/time_counter/background/2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arbelkilani/Clock-view/6ccea2253b76a65db03fcff1353b551a3d9ed0e6/wiki/time_counter/background/2.png -------------------------------------------------------------------------------- /wiki/time_counter/border/1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arbelkilani/Clock-view/6ccea2253b76a65db03fcff1353b551a3d9ed0e6/wiki/time_counter/border/1.png -------------------------------------------------------------------------------- /wiki/time_counter/border/2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arbelkilani/Clock-view/6ccea2253b76a65db03fcff1353b551a3d9ed0e6/wiki/time_counter/border/2.png -------------------------------------------------------------------------------- /wiki/time_counter/border/3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arbelkilani/Clock-view/6ccea2253b76a65db03fcff1353b551a3d9ed0e6/wiki/time_counter/border/3.png -------------------------------------------------------------------------------- /wiki/time_counter/color/1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arbelkilani/Clock-view/6ccea2253b76a65db03fcff1353b551a3d9ed0e6/wiki/time_counter/color/1.png -------------------------------------------------------------------------------- /wiki/time_counter/color/2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arbelkilani/Clock-view/6ccea2253b76a65db03fcff1353b551a3d9ed0e6/wiki/time_counter/color/2.png -------------------------------------------------------------------------------- /wiki/time_counter/font/1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arbelkilani/Clock-view/6ccea2253b76a65db03fcff1353b551a3d9ed0e6/wiki/time_counter/font/1.png -------------------------------------------------------------------------------- /wiki/time_counter/font/2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arbelkilani/Clock-view/6ccea2253b76a65db03fcff1353b551a3d9ed0e6/wiki/time_counter/font/2.png -------------------------------------------------------------------------------- /wiki/time_counter/font/3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arbelkilani/Clock-view/6ccea2253b76a65db03fcff1353b551a3d9ed0e6/wiki/time_counter/font/3.png -------------------------------------------------------------------------------- /wiki/time_counter_screen.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arbelkilani/Clock-view/6ccea2253b76a65db03fcff1353b551a3d9ed0e6/wiki/time_counter_screen.png --------------------------------------------------------------------------------