Compare commits
309 Commits
Author | SHA1 | Date |
---|---|---|
Tibor Kaputa | ddf576aa04 | |
Agnieszka C | 84279de811 | |
tibbi | ac6513332b | |
tibbi | f5ab9462fd | |
tibbi | 9689d4f6fc | |
Tibor Kaputa | 7f739c8b62 | |
Ensar Sarajčić | 9fea2bca1a | |
Ensar Sarajčić | 18c8bf3c7a | |
Ensar Sarajčić | b0ea8d8ef2 | |
Ensar Sarajčić | 27c3aa60d0 | |
Ensar Sarajčić | d36afb3e13 | |
Ensar Sarajčić | b3b0bc84f9 | |
Ensar Sarajčić | b57e782613 | |
Ensar Sarajčić | 13a794fe12 | |
Ensar Sarajčić | c755c67011 | |
Ensar Sarajčić | afe23bfb2e | |
Tibor Kaputa | 899d616eb3 | |
Ensar Sarajčić | c546aab7f1 | |
Ensar Sarajčić | cef9f6e62b | |
Ensar Sarajčić | f21cd4ff49 | |
Ensar Sarajčić | 7533ad1fa2 | |
Ensar Sarajčić | 1600a072ef | |
Ensar Sarajčić | e190cac2a3 | |
Ensar Sarajčić | dabdfdcd7d | |
Ensar Sarajčić | f25601db6b | |
Ensar Sarajčić | 4b7c4350d4 | |
Ensar Sarajčić | d9d3928705 | |
Ensar Sarajčić | 03b0fbb836 | |
Lionel HANNEQUIN | 631d0731c7 | |
Ensar Sarajčić | 4b65350e24 | |
Puppelimies | b37b39e43d | |
Ensar Sarajčić | 88792ccb8d | |
Ensar Sarajčić | efd6c71c63 | |
Ensar Sarajčić | 30c95833c3 | |
Ensar Sarajčić | 410f2759fc | |
Ensar Sarajčić | d2473cfb1f | |
Ensar Sarajčić | d40d5329e5 | |
Ensar Sarajčić | 9d46496807 | |
Ensar Sarajčić | 2404943fe2 | |
Ensar Sarajčić | 3579f61cb9 | |
Ensar Sarajčić | b1b4c46dc3 | |
Ensar Sarajčić | c59108e1ad | |
Ensar Sarajčić | 82c4acc96f | |
Ensar Sarajčić | b290fd0502 | |
Ensar Sarajčić | b5bd119012 | |
Ensar Sarajčić | d9a7598e59 | |
Ensar Sarajčić | 539cf694dc | |
Ensar Sarajčić | 270480ead5 | |
Ensar Sarajčić | 74f4675f19 | |
Ensar Sarajčić | b536626c3c | |
Ensar Sarajčić | 9f6ba77f98 | |
Ensar Sarajčić | f2c8b0828d | |
Ensar Sarajčić | 29081b032c | |
Ensar Sarajčić | 0cfcc9b900 | |
Ensar Sarajčić | a810c0d3ef | |
Ensar Sarajčić | c825bf16a2 | |
Ensar Sarajčić | 2c99bd9c06 | |
Ensar Sarajčić | a1bdd65dbc | |
Ensar Sarajčić | 3c4c4a4001 | |
Ensar Sarajčić | 6c8b301c9f | |
Ensar Sarajčić | d28b51409b | |
Ensar Sarajčić | 6893454559 | |
Ensar Sarajčić | 8ea675a743 | |
Ensar Sarajčić | 6372066b8e | |
Ensar Sarajčić | 28ab74caa1 | |
Ensar Sarajčić | af6691c06a | |
Ensar Sarajčić | c33664b9e7 | |
Ensar Sarajčić | 21a6196896 | |
Ensar Sarajčić | acc8500bd2 | |
Ensar Sarajčić | 8a30781893 | |
Ensar Sarajčić | 0a37a82ac9 | |
Ensar Sarajčić | 7defcd49ff | |
Ensar Sarajčić | 47159f5f54 | |
Ensar Sarajčić | b5b215af6e | |
Ensar Sarajčić | 15dcb65fbc | |
Ensar Sarajčić | 17ac263c5d | |
Ensar Sarajčić | 057cfefb64 | |
Ensar Sarajčić | 34ac99fb63 | |
Ensar Sarajčić | 59537d28bd | |
Ensar Sarajčić | c354d115ee | |
Ensar Sarajčić | eae63898e3 | |
Tibor Kaputa | 680b313372 | |
Ensar Sarajčić | c37ced08a7 | |
Ensar Sarajčić | a3e188529d | |
Ensar Sarajčić | 6296d893b0 | |
Ensar Sarajčić | 2fd3dc5c77 | |
Ensar Sarajčić | 9e3b207509 | |
Ensar Sarajčić | 2f6000db6a | |
Ensar Sarajčić | 50820bd948 | |
Ensar Sarajčić | 17946431ba | |
Ensar Sarajčić | 3323b2fb70 | |
Ensar Sarajčić | 3f901ff290 | |
Ensar Sarajčić | c644def18e | |
Ensar Sarajčić | ee9a539cf5 | |
Ensar Sarajčić | 163e053e1d | |
Ensar Sarajčić | e111bce5f2 | |
Ensar Sarajčić | 0767d76345 | |
Ensar Sarajčić | 50f0be9e20 | |
Ensar Sarajčić | 3a17008fe9 | |
Ensar Sarajčić | 62484fd3c7 | |
Ensar Sarajčić | 2e1821320f | |
Ensar Sarajčić | 10fa019813 | |
Ensar Sarajčić | 132b469b44 | |
Ensar Sarajčić | 81096e35a6 | |
Ensar Sarajčić | 3414295887 | |
Ensar Sarajčić | 87e92df993 | |
Ensar Sarajčić | cd02f52d12 | |
Ensar Sarajčić | de2ce0ea73 | |
Ensar Sarajčić | b61288407b | |
Ensar Sarajčić | 7937a71b0d | |
Tibor Kaputa | b505f7d3ce | |
Ensar Sarajčić | 4c5deb10e4 | |
Ensar Sarajčić | 2a5011fb22 | |
Ensar Sarajčić | 0ff554a835 | |
Ensar Sarajčić | 68f4e32ce2 | |
Ensar Sarajčić | ee7780f9e7 | |
Ensar Sarajčić | 1e1dacf7be | |
Lionel HANNEQUIN | ac8fc71534 | |
gallegonovato | f5a4faa576 | |
Puppelimies | 8bb7b83e39 | |
Tibor Kaputa | 6c3c5f0323 | |
gallegonovato | eda4fdfd40 | |
gallegonovato | 369050728a | |
Lionel HANNEQUIN | efbb7804db | |
Tibor Kaputa | ceed63aaa4 | |
Ensar Sarajčić | 97b5389bc6 | |
Ensar Sarajčić | 0b64092651 | |
Ensar Sarajčić | 2a8d7c2a8c | |
Tibor Kaputa | 1ce4c6ef65 | |
Ensar Sarajčić | 9691b0103c | |
Tibor Kaputa | a183c22062 | |
Ensar Sarajčić | c25feb637a | |
Ensar Sarajčić | 44ed487c98 | |
tibbi | aa381a8a52 | |
tibbi | cfec55d9eb | |
tibbi | 6142287e45 | |
Tibor Kaputa | 3924b33ebb | |
Tibor Kaputa | e73737f2c4 | |
Ensar Sarajčić | da0b5d341c | |
Ensar Sarajčić | 77c8d50cf4 | |
Ensar Sarajčić | 174b2ac803 | |
Ensar Sarajčić | c55e784081 | |
Ensar Sarajčić | 788ef6f01f | |
Ensar Sarajčić | c00d4cc30c | |
Ensar Sarajčić | 2572f7cfbf | |
Ensar Sarajčić | 543362cccb | |
Ensar Sarajčić | 482aef3d65 | |
Ensar Sarajčić | db5b553ce8 | |
Tibor Kaputa | 10c3913fed | |
Tibor Kaputa | aec0fb8e9a | |
fatih ergin | c58a4aa1f2 | |
fatih ergin | 3a40031532 | |
Tibor Kaputa | d1d3b698f2 | |
fatih ergin | 8f1cbec591 | |
Tibor Kaputa | 6747a9a663 | |
Tibor Kaputa | 956040e5ac | |
Milan Šalka | 2ddab7ac59 | |
Tibor Kaputa | 3af5434fad | |
fatih ergin | bc7e02810e | |
fatih ergin | 3e869f4473 | |
Tibor Kaputa | 7d3c398a4b | |
htetoh | fde757eeb5 | |
Tibor Kaputa | 92bba84b70 | |
htetoh | d50323f977 | |
tibbi | 121fcddf90 | |
Tibor Kaputa | 6a351fe3c5 | |
Dejvino | f9a1bb1e04 | |
tibbi | be1ba1a8b9 | |
tibbi | 67754cd060 | |
tibbi | 3d4a1a651b | |
tibbi | b1c2cb84b0 | |
tibbi | 276bbcb7b0 | |
Tibor Kaputa | 16965fb357 | |
Макар Разин | 70188d7731 | |
Slávek Banko | 94b8ec3f19 | |
tibbi | a0cfafb7b1 | |
tibbi | a92a4bf23a | |
tibbi | 4bc55c1282 | |
Tibor Kaputa | dd78bfe8ba | |
Tibor Kaputa | 3ecad0db58 | |
Tibor Kaputa | c44a619cec | |
VfBFan | 5fbdcb3904 | |
P.O | eaeca0920c | |
Oğuz Ersen | 48892c6f13 | |
Rex_sa | f3ff2ae894 | |
Tibor Kaputa | e7070ff04b | |
tibbi | 37a6216b5b | |
Federico Palmieri | a84c22ebf8 | |
tibbi | 017d9f7557 | |
tibbi | 5d9dc308d2 | |
Tibor Kaputa | 3e0f578f6f | |
Linerly | e8b29984ac | |
Sergio Marques | 2d60a5df05 | |
Ahmad0a | 4380996d0b | |
Milo Ivir | ac5b03820c | |
Dan | 53060d644b | |
Dan | 71e0120842 | |
tibbi | f6827cec6d | |
tibbi | 69eac399db | |
tibbi | 3eb2055c48 | |
tibbi | 1edb546cbb | |
tibbi | 0886fe368a | |
tibbi | 6f8db7c15c | |
tibbi | f51efb05cc | |
tibbi | cc156d4152 | |
tibbi | f82331559c | |
tibbi | b96e268a45 | |
Tibor Kaputa | b9f180d9d2 | |
Josep M. Ferrer | 7c8f3f2553 | |
Dan | 43d6c66fd8 | |
Josep M. Ferrer | da5b1061f8 | |
Agnieszka C | e9015fa7a6 | |
rehork | 8d502ef28e | |
tibbi | 869fb11171 | |
Tibor Kaputa | dcb34c2f08 | |
Tibor Kaputa | c3f8b6213e | |
VfBFan | ff7ae31750 | |
Martin Božič | b5af7cf0a3 | |
tibbi | 3602ac5bb1 | |
tibbi | e114faef5a | |
tibbi | e28525f23c | |
Tibor Kaputa | 128f01c751 | |
Martin Božič | 372c6b61d4 | |
tibbi | c3996388f4 | |
tibbi | 93bda81af4 | |
tibbi | 2dc20b3ac9 | |
Tibor Kaputa | 858533e991 | |
darthpaul | c975ab1e82 | |
darthpaul | 98c0f0578e | |
Tibor Kaputa | f20341d920 | |
Tibor Kaputa | cf75472344 | |
Alex | 83ee3b0eb6 | |
darthpaul | 87b678e4bb | |
Tibor Kaputa | 0e726d7d1c | |
tibbi | 662ec91227 | |
Tibor Kaputa | f52c9299fe | |
Tibor Kaputa | b5b7a562bb | |
Tibor Kaputa | 47c8dc34f7 | |
Alex | 780e4c8b53 | |
Alex | 87f96b2aa9 | |
Anonymous | b31152875d | |
Alex | 06bca5ab99 | |
gallegonovato | 0d86e64314 | |
Alex | 770616298f | |
Tibor Kaputa | 25a72290ea | |
tibbi | a8584c1f42 | |
Tibor Kaputa | f66155cb3d | |
Tibor Kaputa | 55eb0a297e | |
Tibor Kaputa | 1489c89736 | |
Tibor Kaputa | 5be7abc86a | |
Tibor Kaputa | fca50455d2 | |
Anonymous | bda82d00f5 | |
Trendyne | 94cd66aadf | |
bgo-eiu | a85eeec1a2 | |
Anonymous | 4e452be4a4 | |
bgo-eiu | 1b4102b80c | |
darthpaul | 75eca9e3f0 | |
Alex | e3b8b943e2 | |
Alex | b313a2f33b | |
Rex_sa | 2bfeda0041 | |
darthpaul | 28bda12ae9 | |
darthpaul | cea57e9db0 | |
Anonymous | acc834ca46 | |
Alex | 39339cf973 | |
Vri 🌈 | dfa252f1ab | |
Mikkel-T | b67d42a9d0 | |
gallegonovato | f2595cf15b | |
NPL | a0f3d6a6fe | |
gallegonovato | 671dcd330f | |
gallegonovato | 0d2025fdd0 | |
gallegonovato | a2016cc454 | |
tibbi | dc66f8bd66 | |
tibbi | 594b227ab2 | |
tibbi | 8c20fdbced | |
tibbi | 610d9e6728 | |
tibbi | e18c4b9541 | |
Tibor Kaputa | e533af5e1c | |
paula katos | ce297ccd11 | |
atilluF | a7589478e4 | |
en2sv | 17914a9220 | |
tibbi | 73a81d533d | |
Tibor Kaputa | 14116b9031 | |
words wave | cdf3b77a3e | |
words wave | 3dfca24a94 | |
words wave | 9a22d24516 | |
Kovacs Bea | d2cdb3af06 | |
Kovacs Bea | 1bd651480d | |
Milo Ivir | 6f82830a36 | |
Stefan Ivanov | f74d16c42c | |
Stefan Ivanov | de51245a89 | |
Stefan Ivanov | f82d664078 | |
Josep M. Ferrer | 3f2fd4751d | |
Agnieszka C | 3205c422ea | |
tibbi | 43c4bbb0a1 | |
tibbi | 9931cd43c4 | |
tibbi | f039ec9f40 | |
tibbi | 5713537fc9 | |
tibbi | d73a5f17c6 | |
Tibor Kaputa | b884038062 | |
Priit Jõerüüt | 41dcf874e9 | |
Worldfast | 51293cd85c | |
gallegonovato | 1460e80297 | |
kyoya | 64a4bccf37 | |
gallegonovato | aa118984c0 | |
Josep M. Ferrer | c4e40501b5 | |
Milo Ivir | 14ed2c2c3a | |
tibbi | 1c43813762 | |
tibbi | f33c0d611c | |
tibbi | 3a65836e76 |
55
CHANGELOG.md
|
@ -1,6 +1,61 @@
|
|||
Changelog
|
||||
==========
|
||||
|
||||
Version 5.10.1 *(2023-10-18)*
|
||||
----------------------------
|
||||
|
||||
* Added some UI and translation improvements
|
||||
|
||||
Version 5.10.0 *(2023-09-07)*
|
||||
----------------------------
|
||||
|
||||
* Added a Sleep timer
|
||||
* Added some UI and translation improvements
|
||||
|
||||
Version 5.9.2 *(2023-05-15)*
|
||||
----------------------------
|
||||
|
||||
* Added some UI and translation improvements
|
||||
|
||||
Version 5.9.1 *(2023-03-25)*
|
||||
----------------------------
|
||||
|
||||
* Added some UI, stability and translation improvements
|
||||
|
||||
Version 5.9.0 *(2022-12-21)*
|
||||
----------------------------
|
||||
|
||||
* Use Material You design by default on Android 12+
|
||||
* Increased minimal required Android OS version to 6
|
||||
* Added some UI, stability and translation improvements
|
||||
|
||||
Version 5.8.4 *(2022-11-17)*
|
||||
----------------------------
|
||||
|
||||
* Allow changing the flashlight brightness on Android 13+
|
||||
* Added a Bright display settings tile
|
||||
* Fixed SOS timing
|
||||
* Added some translation and UX improvements
|
||||
|
||||
Version 5.8.3 *(2022-11-15)*
|
||||
----------------------------
|
||||
|
||||
* Allow changing the flashlight brightness on Android 13+
|
||||
* Added a Bright display settings tile
|
||||
* Fixed SOS timing
|
||||
* Added some translation and UX improvements
|
||||
|
||||
Version 5.8.2 *(2022-10-06)*
|
||||
----------------------------
|
||||
|
||||
* Adding a Get Simple Phone button into the About section
|
||||
* Added some translation and UX improvements
|
||||
|
||||
Version 5.8.1 *(2022-09-11)*
|
||||
----------------------------
|
||||
|
||||
* Added some translation and UX improvements
|
||||
|
||||
Version 5.8.0 *(2022-08-17)*
|
||||
----------------------------
|
||||
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
### Reporting
|
||||
Before you report something, read the reporting rules [here](https://github.com/SimpleMobileTools/General-Discussion#how-do-i-suggest-an-improvement-ask-a-question-or-report-an-issue) please.
|
||||
|
||||
### Contributing as a developer
|
||||
Some instructions about code style and everything that has to be done to increase the change of your code getting accepted can be found at the [General Discussion](https://github.com/SimpleMobileTools/General-Discussion#contribution-rules-for-developers) section.
|
||||
|
||||
### Contributing as a non developer
|
||||
In case you just want to for example improve a translation, you can find the way of doing it [here](https://github.com/SimpleMobileTools/General-Discussion#how-can-i-suggest-an-edit-to-a-file).
|
|
@ -32,10 +32,10 @@ Telegram:
|
|||
https://t.me/SimpleMobileTools
|
||||
|
||||
<a href='https://play.google.com/store/apps/details?id=com.simplemobiletools.flashlight'><img src='https://simplemobiletools.com/images/button-google-play.svg' alt='Get it on Google Play' height=45/></a>
|
||||
<a href='https://f-droid.org/packages/com.simplemobiletools.flashlight'><img src='https://simplemobiletools.com/images/button-f-droid.png' alt='Get it on F-Droid' height=45 ></a>
|
||||
<a href='https://f-droid.org/packages/com.simplemobiletools.flashlight'><img src='https://simplemobiletools.com/images/button-fdroid.svg' alt='Get it on F-Droid' height=45 ></a>
|
||||
|
||||
<div style="display:flex;">
|
||||
<img alt="App image" src="fastlane/metadata/android/en-GB/images/phoneScreenshots/1_en-GB.jpeg" width="30%">
|
||||
<img alt="App image" src="fastlane/metadata/android/en-GB/images/phoneScreenshots/2_en-GB.jpeg" width="30%">
|
||||
<img alt="App image" src="fastlane/metadata/android/en-GB/images/phoneScreenshots/3_en-GB.jpeg" width="30%">
|
||||
<img alt="App image" src="fastlane/metadata/android/en-US/images/phoneScreenshots/1_en-US.jpeg" width="30%">
|
||||
<img alt="App image" src="fastlane/metadata/android/en-US/images/phoneScreenshots/2_en-US.jpeg" width="30%">
|
||||
<img alt="App image" src="fastlane/metadata/android/en-US/images/phoneScreenshots/3_en-US.jpeg" width="30%">
|
||||
</div>
|
||||
|
|
|
@ -1,68 +0,0 @@
|
|||
apply plugin: 'com.android.application'
|
||||
apply plugin: 'kotlin-android'
|
||||
apply plugin: 'kotlin-android-extensions'
|
||||
|
||||
def keystorePropertiesFile = rootProject.file("keystore.properties")
|
||||
def keystoreProperties = new Properties()
|
||||
if (keystorePropertiesFile.exists()) {
|
||||
keystoreProperties.load(new FileInputStream(keystorePropertiesFile))
|
||||
}
|
||||
|
||||
android {
|
||||
compileSdkVersion 33
|
||||
|
||||
defaultConfig {
|
||||
applicationId "com.simplemobiletools.flashlight"
|
||||
minSdkVersion 21
|
||||
targetSdkVersion 33
|
||||
versionCode 57
|
||||
versionName "5.8.0"
|
||||
setProperty("archivesBaseName", "flashlight")
|
||||
}
|
||||
|
||||
signingConfigs {
|
||||
if (keystorePropertiesFile.exists()) {
|
||||
release {
|
||||
keyAlias keystoreProperties['keyAlias']
|
||||
keyPassword keystoreProperties['keyPassword']
|
||||
storeFile file(keystoreProperties['storeFile'])
|
||||
storePassword keystoreProperties['storePassword']
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
buildTypes {
|
||||
debug {
|
||||
applicationIdSuffix ".debug"
|
||||
}
|
||||
release {
|
||||
minifyEnabled true
|
||||
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
|
||||
if (keystorePropertiesFile.exists()) {
|
||||
signingConfig signingConfigs.release
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
flavorDimensions "variants"
|
||||
productFlavors {
|
||||
core {}
|
||||
fdroid {}
|
||||
prepaid {}
|
||||
}
|
||||
|
||||
sourceSets {
|
||||
main.java.srcDirs += 'src/main/kotlin'
|
||||
}
|
||||
|
||||
lintOptions {
|
||||
checkReleaseBuilds false
|
||||
abortOnError false
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation 'com.github.SimpleMobileTools:Simple-Commons:28a68aa6c0'
|
||||
implementation 'org.greenrobot:eventbus:3.3.1'
|
||||
implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
|
||||
}
|
|
@ -0,0 +1,111 @@
|
|||
import java.io.FileInputStream
|
||||
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
|
||||
import org.jetbrains.kotlin.konan.properties.Properties
|
||||
|
||||
plugins {
|
||||
alias(libs.plugins.android)
|
||||
alias(libs.plugins.kotlinAndroid)
|
||||
base
|
||||
}
|
||||
|
||||
base {
|
||||
archivesName.set("flashlight")
|
||||
}
|
||||
|
||||
val keystorePropertiesFile: File = rootProject.file("keystore.properties")
|
||||
val keystoreProperties = Properties()
|
||||
if (keystorePropertiesFile.exists()) {
|
||||
keystoreProperties.load(FileInputStream(keystorePropertiesFile))
|
||||
}
|
||||
|
||||
android {
|
||||
compileSdk = project.libs.versions.app.build.compileSDKVersion.get().toInt()
|
||||
|
||||
defaultConfig {
|
||||
applicationId = libs.versions.app.version.appId.get()
|
||||
minSdk = project.libs.versions.app.build.minimumSDK.get().toInt()
|
||||
targetSdk = project.libs.versions.app.build.targetSDK.get().toInt()
|
||||
versionName = project.libs.versions.app.version.versionName.get()
|
||||
versionCode = project.libs.versions.app.version.versionCode.get().toInt()
|
||||
}
|
||||
|
||||
signingConfigs {
|
||||
if (keystorePropertiesFile.exists()) {
|
||||
register("release") {
|
||||
keyAlias = keystoreProperties.getProperty("keyAlias")
|
||||
keyPassword = keystoreProperties.getProperty("keyPassword")
|
||||
storeFile = file(keystoreProperties.getProperty("storeFile"))
|
||||
storePassword = keystoreProperties.getProperty("storePassword")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
buildFeatures {
|
||||
viewBinding = true
|
||||
buildConfig = true
|
||||
compose = true
|
||||
}
|
||||
|
||||
composeOptions {
|
||||
kotlinCompilerExtensionVersion = libs.versions.composeCompiler.get()
|
||||
}
|
||||
|
||||
buildTypes {
|
||||
debug {
|
||||
applicationIdSuffix = ".debug"
|
||||
}
|
||||
release {
|
||||
isMinifyEnabled = true
|
||||
proguardFiles(
|
||||
getDefaultProguardFile("proguard-android-optimize.txt"),
|
||||
"proguard-rules.pro"
|
||||
)
|
||||
if (keystorePropertiesFile.exists()) {
|
||||
signingConfig = signingConfigs.getByName("release")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
flavorDimensions.add("variants")
|
||||
productFlavors {
|
||||
register("core")
|
||||
register("fdroid")
|
||||
register("prepaid")
|
||||
}
|
||||
|
||||
sourceSets {
|
||||
getByName("main").java.srcDirs("src/main/kotlin")
|
||||
}
|
||||
|
||||
compileOptions {
|
||||
val currentJavaVersionFromLibs = JavaVersion.valueOf(libs.versions.app.build.javaVersion.get().toString())
|
||||
sourceCompatibility = currentJavaVersionFromLibs
|
||||
targetCompatibility = currentJavaVersionFromLibs
|
||||
}
|
||||
|
||||
tasks.withType<KotlinCompile> {
|
||||
kotlinOptions.jvmTarget = project.libs.versions.app.build.kotlinJVMTarget.get()
|
||||
kotlinOptions.freeCompilerArgs = listOf(
|
||||
"-opt-in=kotlin.RequiresOptIn",
|
||||
"-opt-in=androidx.compose.material3.ExperimentalMaterial3Api",
|
||||
"-opt-in=androidx.compose.material.ExperimentalMaterialApi",
|
||||
"-opt-in=androidx.compose.foundation.ExperimentalFoundationApi",
|
||||
"-Xcontext-receivers"
|
||||
)
|
||||
}
|
||||
|
||||
namespace = libs.versions.app.version.appId.get()
|
||||
|
||||
lint {
|
||||
checkReleaseBuilds = false
|
||||
abortOnError = false
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation(libs.simple.tools.commons)
|
||||
|
||||
implementation(libs.bundles.lifecycle)
|
||||
implementation(libs.bundles.compose)
|
||||
debugImplementation(libs.bundles.compose.preview)
|
||||
}
|
|
@ -1,6 +0,0 @@
|
|||
# EventBus
|
||||
-keepattributes *Annotation*
|
||||
-keepclassmembers class ** {
|
||||
@org.greenrobot.eventbus.Subscribe <methods>;
|
||||
}
|
||||
-keep enum org.greenrobot.eventbus.ThreadMode { *; }
|
|
@ -1,7 +1,6 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
package="com.simplemobiletools.flashlight"
|
||||
android:installLocation="auto">
|
||||
|
||||
<uses-permission
|
||||
|
@ -10,6 +9,7 @@
|
|||
|
||||
<uses-permission android:name="android.permission.FLASHLIGHT" />
|
||||
|
||||
<uses-permission android:name="android.permission.SCHEDULE_EXACT_ALARM" />
|
||||
<uses-permission
|
||||
android:name="android.permission.USE_FINGERPRINT"
|
||||
tools:node="remove" />
|
||||
|
@ -23,6 +23,7 @@
|
|||
android:allowBackup="true"
|
||||
android:icon="@mipmap/ic_launcher"
|
||||
android:label="@string/app_launcher_name"
|
||||
android:localeConfig="@xml/locale_config"
|
||||
android:roundIcon="@mipmap/ic_launcher"
|
||||
android:supportsRtl="true"
|
||||
android:theme="@style/AppTheme">
|
||||
|
@ -64,6 +65,7 @@
|
|||
android:name=".activities.BrightDisplayActivity"
|
||||
android:exported="false"
|
||||
android:label="@string/bright_display"
|
||||
android:launchMode="singleInstance"
|
||||
android:theme="@style/FullScreenTheme" />
|
||||
|
||||
<activity
|
||||
|
@ -105,7 +107,7 @@
|
|||
<receiver
|
||||
android:name=".helpers.MyWidgetTorchProvider"
|
||||
android:exported="true"
|
||||
android:icon="@drawable/ic_flashlight"
|
||||
android:icon="@drawable/ic_flashlight_vector"
|
||||
android:label="@string/app_launcher_name">
|
||||
<intent-filter>
|
||||
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
|
||||
|
@ -119,7 +121,7 @@
|
|||
<receiver
|
||||
android:name=".helpers.MyWidgetBrightDisplayProvider"
|
||||
android:exported="true"
|
||||
android:icon="@drawable/ic_bright_display"
|
||||
android:icon="@drawable/ic_bright_display_vector"
|
||||
android:label="@string/bright_display">
|
||||
<intent-filter>
|
||||
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
|
||||
|
@ -130,10 +132,13 @@
|
|||
android:resource="@xml/widget_bright_display" />
|
||||
</receiver>
|
||||
|
||||
<receiver android:name=".helpers.ShutDownReceiver"
|
||||
android:exported="false" />
|
||||
|
||||
<service
|
||||
android:name=".helpers.MyTileService"
|
||||
android:name=".helpers.FlashlightTileService"
|
||||
android:exported="true"
|
||||
android:icon="@drawable/img_widget_preview"
|
||||
android:icon="@drawable/img_torch_widget_preview"
|
||||
android:label="@string/app_launcher_name"
|
||||
android:permission="android.permission.BIND_QUICK_SETTINGS_TILE">
|
||||
<intent-filter>
|
||||
|
@ -141,6 +146,17 @@
|
|||
</intent-filter>
|
||||
</service>
|
||||
|
||||
<service
|
||||
android:name=".helpers.BrightDisplayTileService"
|
||||
android:exported="true"
|
||||
android:icon="@drawable/img_bright_display_widget_preview"
|
||||
android:label="@string/bright_display"
|
||||
android:permission="android.permission.BIND_QUICK_SETTINGS_TILE">
|
||||
<intent-filter>
|
||||
<action android:name="android.service.quicksettings.action.QS_TILE" />
|
||||
</intent-filter>
|
||||
</service>
|
||||
|
||||
<activity-alias
|
||||
android:name=".activities.SplashActivity.Red"
|
||||
android:enabled="false"
|
||||
|
|
|
@ -1,48 +1,97 @@
|
|||
package com.simplemobiletools.flashlight.activities
|
||||
|
||||
import android.app.Application
|
||||
import android.content.pm.ActivityInfo
|
||||
import android.graphics.drawable.ColorDrawable
|
||||
import android.os.Bundle
|
||||
import android.view.WindowManager
|
||||
import com.simplemobiletools.commons.dialogs.ColorPickerDialog
|
||||
import com.simplemobiletools.commons.extensions.applyColorFilter
|
||||
import androidx.activity.ComponentActivity
|
||||
import androidx.activity.compose.setContent
|
||||
import androidx.activity.viewModels
|
||||
import androidx.annotation.ColorInt
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.derivedStateOf
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.lifecycle.AndroidViewModel
|
||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import com.simplemobiletools.commons.compose.alert_dialog.rememberAlertDialogState
|
||||
import com.simplemobiletools.commons.compose.extensions.enableEdgeToEdgeSimple
|
||||
import com.simplemobiletools.commons.compose.extensions.setShowWhenLockedCompat
|
||||
import com.simplemobiletools.commons.compose.extensions.setTurnScreenOnCompat
|
||||
import com.simplemobiletools.commons.compose.theme.AppThemeSurface
|
||||
import com.simplemobiletools.commons.dialogs.ColorPickerAlertDialog
|
||||
import com.simplemobiletools.commons.extensions.getContrastColor
|
||||
import com.simplemobiletools.flashlight.R
|
||||
import com.simplemobiletools.commons.extensions.getFormattedDuration
|
||||
import com.simplemobiletools.flashlight.extensions.config
|
||||
import kotlinx.android.synthetic.main.activity_bright_display.*
|
||||
import com.simplemobiletools.flashlight.helpers.SleepTimer
|
||||
import com.simplemobiletools.flashlight.helpers.stopSleepTimerCountDown
|
||||
import com.simplemobiletools.flashlight.screens.BrightDisplayScreen
|
||||
import com.simplemobiletools.flashlight.views.AnimatedSleepTimer
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.asStateFlow
|
||||
import kotlinx.coroutines.flow.launchIn
|
||||
import kotlinx.coroutines.flow.onEach
|
||||
import kotlin.system.exitProcess
|
||||
|
||||
class BrightDisplayActivity : ComponentActivity() {
|
||||
private val viewModel by viewModels<BrightDisplayViewModel>()
|
||||
private val preferences by lazy { config }
|
||||
|
||||
class BrightDisplayActivity : SimpleActivity() {
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
window.addFlags(
|
||||
WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD or
|
||||
WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED or
|
||||
WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON or
|
||||
WindowManager.LayoutParams.FLAG_FULLSCREEN
|
||||
)
|
||||
|
||||
useDynamicTheme = false
|
||||
setShowWhenLockedCompat(true)
|
||||
setTurnScreenOnCompat(true)
|
||||
super.onCreate(savedInstanceState)
|
||||
setContentView(R.layout.activity_bright_display)
|
||||
supportActionBar?.hide()
|
||||
setBackgroundColor(config.brightDisplayColor)
|
||||
enableEdgeToEdgeSimple()
|
||||
setContent {
|
||||
AppThemeSurface {
|
||||
val brightDisplayColor by preferences.brightDisplayColorFlow.collectAsStateWithLifecycle(preferences.brightDisplayColor)
|
||||
val colorPickerDialogState = getColorPickerDialogState(brightDisplayColor)
|
||||
|
||||
bright_display_change_color.setOnClickListener {
|
||||
ColorPickerDialog(this, config.brightDisplayColor, true, currentColorCallback = {
|
||||
setBackgroundColor(it)
|
||||
}) { wasPositivePressed, color ->
|
||||
if (wasPositivePressed) {
|
||||
config.brightDisplayColor = color
|
||||
|
||||
val contrastColor = color.getContrastColor()
|
||||
bright_display_change_color.setTextColor(contrastColor)
|
||||
bright_display_change_color.background.applyColorFilter(contrastColor)
|
||||
} else {
|
||||
setBackgroundColor(config.brightDisplayColor)
|
||||
}
|
||||
ScreenContent(colorPickerDialogState::show)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun getColorPickerDialogState(
|
||||
@ColorInt
|
||||
brightDisplayColor: Int
|
||||
) = rememberAlertDialogState().apply {
|
||||
DialogMember {
|
||||
ColorPickerAlertDialog(
|
||||
alertDialogState = this,
|
||||
color = brightDisplayColor,
|
||||
removeDimmedBackground = true,
|
||||
onActiveColorChange = viewModel::updateBackgroundColor,
|
||||
onButtonPressed = { wasPositivePressed, color ->
|
||||
if (wasPositivePressed) {
|
||||
config.brightDisplayColor = color
|
||||
viewModel.updateBackgroundColor(color)
|
||||
} else {
|
||||
viewModel.updateBackgroundColor(config.brightDisplayColor)
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun ScreenContent(onChangeColorButtonPress: () -> Unit) {
|
||||
val backgroundColor by viewModel.backgroundColor.collectAsStateWithLifecycle()
|
||||
val contrastColor by remember { derivedStateOf { backgroundColor.getContrastColor() } }
|
||||
val timerVisible by viewModel.timerVisible.collectAsStateWithLifecycle()
|
||||
val timerText by viewModel.timerText.collectAsStateWithLifecycle()
|
||||
BrightDisplayScreen(
|
||||
backgroundColor = backgroundColor,
|
||||
contrastColor = contrastColor,
|
||||
onChangeColorPress = onChangeColorButtonPress,
|
||||
sleepTimer = {
|
||||
AnimatedSleepTimer(timerText = timerText, timerVisible = timerVisible, onTimerClosePress = ::stopSleepTimer)
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
|
||||
|
@ -56,17 +105,51 @@ class BrightDisplayActivity : SimpleActivity() {
|
|||
toggleBrightness(false)
|
||||
}
|
||||
|
||||
private fun setBackgroundColor(color: Int) {
|
||||
bright_display.background = ColorDrawable(color)
|
||||
|
||||
val contrastColor = config.brightDisplayColor.getContrastColor()
|
||||
bright_display_change_color.setTextColor(contrastColor)
|
||||
bright_display_change_color.background.applyColorFilter(contrastColor)
|
||||
}
|
||||
|
||||
private fun toggleBrightness(increase: Boolean) {
|
||||
val layout = window.attributes
|
||||
layout.screenBrightness = (if (increase) 1 else 0).toFloat()
|
||||
window.attributes = layout
|
||||
}
|
||||
|
||||
private fun stopSleepTimer() {
|
||||
viewModel.hideTimer()
|
||||
stopSleepTimerCountDown()
|
||||
}
|
||||
|
||||
|
||||
internal class BrightDisplayViewModel(
|
||||
application: Application
|
||||
) : AndroidViewModel(application) {
|
||||
|
||||
|
||||
private val _timerText: MutableStateFlow<String> = MutableStateFlow("00:00")
|
||||
val timerText = _timerText.asStateFlow()
|
||||
|
||||
private val _timerVisible: MutableStateFlow<Boolean> = MutableStateFlow(false)
|
||||
val timerVisible = _timerVisible.asStateFlow()
|
||||
|
||||
private val _backgroundColor: MutableStateFlow<Int> = MutableStateFlow(application.config.brightDisplayColor)
|
||||
val backgroundColor = _backgroundColor.asStateFlow()
|
||||
|
||||
init {
|
||||
SleepTimer.timeLeft
|
||||
.onEach { seconds ->
|
||||
_timerText.value = seconds.getFormattedDuration()
|
||||
_timerVisible.value = true
|
||||
|
||||
if (seconds == 0) {
|
||||
exitProcess(0)
|
||||
}
|
||||
}
|
||||
.launchIn(viewModelScope)
|
||||
}
|
||||
|
||||
fun updateBackgroundColor(color: Int) {
|
||||
_backgroundColor.value = color
|
||||
}
|
||||
|
||||
fun hideTimer() {
|
||||
_timerVisible.value = false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,287 +1,404 @@
|
|||
package com.simplemobiletools.flashlight.activities
|
||||
|
||||
import android.Manifest
|
||||
import android.annotation.SuppressLint
|
||||
import android.app.AlarmManager
|
||||
import android.app.Application
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.content.pm.ActivityInfo
|
||||
import android.content.pm.PackageManager
|
||||
import android.content.pm.ShortcutInfo
|
||||
import android.content.res.ColorStateList
|
||||
import android.graphics.drawable.Icon
|
||||
import android.graphics.drawable.LayerDrawable
|
||||
import android.os.Bundle
|
||||
import android.view.WindowManager
|
||||
import android.widget.ImageView
|
||||
import androidx.activity.ComponentActivity
|
||||
import androidx.activity.compose.ManagedActivityResultLauncher
|
||||
import androidx.activity.compose.rememberLauncherForActivityResult
|
||||
import androidx.activity.compose.setContent
|
||||
import androidx.activity.result.contract.ActivityResultContracts
|
||||
import androidx.activity.viewModels
|
||||
import androidx.compose.runtime.*
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.lifecycle.AndroidViewModel
|
||||
import androidx.lifecycle.Lifecycle
|
||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import com.google.android.material.math.MathUtils
|
||||
import com.simplemobiletools.commons.compose.alert_dialog.AlertDialogState
|
||||
import com.simplemobiletools.commons.compose.alert_dialog.rememberAlertDialogState
|
||||
import com.simplemobiletools.commons.compose.extensions.*
|
||||
import com.simplemobiletools.commons.compose.theme.AppThemeSurface
|
||||
import com.simplemobiletools.commons.dialogs.*
|
||||
import com.simplemobiletools.commons.extensions.*
|
||||
import com.simplemobiletools.commons.helpers.LICENSE_EVENT_BUS
|
||||
import com.simplemobiletools.commons.helpers.PERMISSION_CAMERA
|
||||
import com.simplemobiletools.commons.helpers.isNougatMR1Plus
|
||||
import com.simplemobiletools.commons.helpers.isNougatPlus
|
||||
import com.simplemobiletools.commons.helpers.*
|
||||
import com.simplemobiletools.commons.models.FAQItem
|
||||
import com.simplemobiletools.commons.models.RadioItem
|
||||
import com.simplemobiletools.flashlight.BuildConfig
|
||||
import com.simplemobiletools.flashlight.R
|
||||
import com.simplemobiletools.flashlight.dialogs.SleepTimerCustomAlertDialog
|
||||
import com.simplemobiletools.flashlight.extensions.config
|
||||
import com.simplemobiletools.flashlight.helpers.MyCameraImpl
|
||||
import com.simplemobiletools.flashlight.models.Events
|
||||
import kotlinx.android.synthetic.main.activity_main.*
|
||||
import org.greenrobot.eventbus.EventBus
|
||||
import org.greenrobot.eventbus.Subscribe
|
||||
import com.simplemobiletools.flashlight.extensions.startAboutActivity
|
||||
import com.simplemobiletools.flashlight.helpers.*
|
||||
import com.simplemobiletools.flashlight.screens.*
|
||||
import com.simplemobiletools.flashlight.views.AnimatedSleepTimer
|
||||
import kotlinx.collections.immutable.toImmutableList
|
||||
import kotlinx.coroutines.flow.*
|
||||
import java.util.*
|
||||
import kotlin.system.exitProcess
|
||||
|
||||
class MainActivity : SimpleActivity() {
|
||||
private val MAX_STROBO_DELAY = 2000L
|
||||
private val MIN_STROBO_DELAY = 10L
|
||||
private val FLASHLIGHT_STATE = "flashlight_state"
|
||||
private val STROBOSCOPE_STATE = "stroboscope_state"
|
||||
class MainActivity : ComponentActivity() {
|
||||
companion object {
|
||||
private const val MAX_STROBO_DELAY = 2000L
|
||||
private const val MIN_STROBO_DELAY = 10L
|
||||
}
|
||||
|
||||
private var mBus: EventBus? = null
|
||||
private var mCameraImpl: MyCameraImpl? = null
|
||||
private var mIsFlashlightOn = false
|
||||
private var reTurnFlashlightOn = true
|
||||
private val preferences by lazy { config }
|
||||
private val viewModel by viewModels<MainViewModel>()
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
setContentView(R.layout.activity_main)
|
||||
appLaunched(BuildConfig.APPLICATION_ID)
|
||||
setupOptionsMenu()
|
||||
|
||||
mBus = EventBus.getDefault()
|
||||
changeIconColor(getContrastColor(), stroboscope_btn)
|
||||
enableEdgeToEdgeSimple()
|
||||
setContent {
|
||||
AppThemeSurface {
|
||||
val showMoreApps = onEventValue { !resources.getBoolean(com.simplemobiletools.commons.R.bool.hide_google_relations) }
|
||||
val sosPermissionLauncher = rememberLauncherForActivityResult(
|
||||
contract = ActivityResultContracts.RequestPermission(),
|
||||
onResult = getPermissionResultHandler(true)
|
||||
)
|
||||
val stroboscopePermissionLauncher = rememberLauncherForActivityResult(
|
||||
contract = ActivityResultContracts.RequestPermission(),
|
||||
onResult = getPermissionResultHandler(false)
|
||||
)
|
||||
|
||||
bright_display_btn.setOnClickListener {
|
||||
reTurnFlashlightOn = false
|
||||
startActivity(Intent(applicationContext, BrightDisplayActivity::class.java))
|
||||
val sleepTimerCustomDialogState = getSleepTimerCustomDialogState()
|
||||
val sleepTimerDialogState = getSleepTimerDialogState(showCustomSleepTimerDialog = sleepTimerCustomDialogState::show)
|
||||
val sleepTimerPermissionDialogState = getSleepTimerPermissionDialogState(showSleepTimerDialog = sleepTimerDialogState::show)
|
||||
|
||||
MainScreen(
|
||||
flashlightButton = {
|
||||
val flashlightActive by viewModel.flashlightOn.collectAsStateWithLifecycle()
|
||||
|
||||
FlashlightButton(
|
||||
onFlashlightPress = { viewModel.toggleFlashlight() },
|
||||
flashlightActive = flashlightActive,
|
||||
)
|
||||
},
|
||||
brightDisplayButton = {
|
||||
val showBrightDisplayButton by preferences.brightDisplayFlow.collectAsStateWithLifecycle(config.brightDisplay)
|
||||
if (showBrightDisplayButton) {
|
||||
BrightDisplayButton(
|
||||
onBrightDisplayPress = {
|
||||
startActivity(Intent(applicationContext, BrightDisplayActivity::class.java))
|
||||
}
|
||||
)
|
||||
}
|
||||
},
|
||||
sosButton = {
|
||||
val showSosButton by preferences.sosFlow.collectAsStateWithLifecycle(config.sos)
|
||||
val sosActive by viewModel.sosActive.collectAsStateWithLifecycle()
|
||||
|
||||
if (showSosButton) {
|
||||
SosButton(
|
||||
sosActive = sosActive,
|
||||
onSosButtonPress = {
|
||||
toggleStroboscope(true, sosPermissionLauncher)
|
||||
},
|
||||
)
|
||||
}
|
||||
},
|
||||
stroboscopeButton = {
|
||||
val showStroboscopeButton by preferences.stroboscopeFlow.collectAsStateWithLifecycle(config.stroboscope)
|
||||
val stroboscopeActive by viewModel.stroboscopeActive.collectAsStateWithLifecycle()
|
||||
|
||||
if (showStroboscopeButton) {
|
||||
StroboscopeButton(
|
||||
stroboscopeActive = stroboscopeActive,
|
||||
onStroboscopeButtonPress = {
|
||||
toggleStroboscope(false, stroboscopePermissionLauncher)
|
||||
},
|
||||
)
|
||||
}
|
||||
},
|
||||
slidersSection = {
|
||||
val brightnessBarVisible by viewModel.brightnessBarVisible.collectAsStateWithLifecycle()
|
||||
val brightnessBarValue by viewModel.brightnessBarValue.collectAsStateWithLifecycle()
|
||||
val stroboscopeBarVisible by viewModel.stroboscopeBarVisible.collectAsStateWithLifecycle()
|
||||
val stroboscopeBarValue by viewModel.stroboscopeBarValue.collectAsStateWithLifecycle()
|
||||
|
||||
MainScreenSlidersSection(
|
||||
showBrightnessBar = brightnessBarVisible,
|
||||
brightnessBarValue = brightnessBarValue,
|
||||
onBrightnessBarValueChange = viewModel::updateBrightnessBarValue,
|
||||
showStroboscopeBar = stroboscopeBarVisible,
|
||||
stroboscopeBarValue = stroboscopeBarValue,
|
||||
onStroboscopeBarValueChange = viewModel::updateStroboscopeBarValue,
|
||||
)
|
||||
},
|
||||
sleepTimer = {
|
||||
val timerVisible by viewModel.timerVisible.collectAsStateWithLifecycle()
|
||||
val timerText by viewModel.timerText.collectAsStateWithLifecycle()
|
||||
|
||||
AnimatedSleepTimer(
|
||||
timerText = timerText,
|
||||
timerVisible = timerVisible,
|
||||
onTimerClosePress = { stopSleepTimer() },
|
||||
)
|
||||
},
|
||||
showMoreApps = showMoreApps,
|
||||
openSettings = ::launchSettings,
|
||||
openAbout = ::launchAbout,
|
||||
openSleepTimer = {
|
||||
showSleepTimerPermission(
|
||||
requestAlarmPermission = sleepTimerPermissionDialogState::show,
|
||||
onNoPermissionRequired = sleepTimerDialogState::show
|
||||
)
|
||||
},
|
||||
moreAppsFromUs = ::launchMoreAppsFromUsIntent
|
||||
)
|
||||
|
||||
AppLaunched()
|
||||
CheckAppOnSdCard()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun SleepTimerRadioDialog(
|
||||
alertDialogState: AlertDialogState,
|
||||
onCustomValueSelected: () -> Unit
|
||||
) {
|
||||
val lastSleepTimerSeconds by preferences.lastSleepTimerSecondsFlow.collectAsStateWithLifecycle(preferences.lastSleepTimerSeconds)
|
||||
val items by remember {
|
||||
derivedStateOf {
|
||||
buildSleepTimerRadioItemsList(lastSleepTimerSeconds)
|
||||
}
|
||||
}
|
||||
|
||||
flashlight_btn.setOnClickListener {
|
||||
mCameraImpl!!.toggleFlashlight()
|
||||
RadioGroupAlertDialog(
|
||||
alertDialogState = alertDialogState,
|
||||
items = items,
|
||||
selectedItemId = preferences.lastSleepTimerSeconds,
|
||||
callback = {
|
||||
when {
|
||||
it == -1 -> onCustomValueSelected()
|
||||
it as Int > 0 -> pickedSleepTimer(it)
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
private fun buildSleepTimerRadioItemsList(
|
||||
lastSleepTimerSeconds: Int
|
||||
) = buildList<RadioItem> {
|
||||
addAll(listOf(10, 30, 60, 5 * 60, 10 * 60, 30 * 60).map {
|
||||
RadioItem(it, secondsToString(it))
|
||||
})
|
||||
|
||||
if (none { it.id == lastSleepTimerSeconds }) {
|
||||
add(RadioItem(lastSleepTimerSeconds, secondsToString(lastSleepTimerSeconds)))
|
||||
}
|
||||
|
||||
sos_btn.setOnClickListener {
|
||||
toggleStroboscope(true)
|
||||
sortBy { it.id }
|
||||
add(RadioItem(-1, getString(com.simplemobiletools.commons.R.string.custom)))
|
||||
}.toImmutableList()
|
||||
|
||||
@Composable
|
||||
private fun AppLaunched(
|
||||
donateAlertDialogState: AlertDialogState = getDonateAlertDialogState(),
|
||||
rateStarsAlertDialogState: AlertDialogState = getRateStarsAlertDialogState(),
|
||||
) {
|
||||
LaunchedEffect(Unit) {
|
||||
appLaunchedCompose(
|
||||
appId = BuildConfig.APPLICATION_ID,
|
||||
showDonateDialog = donateAlertDialogState::show,
|
||||
showRateUsDialog = rateStarsAlertDialogState::show,
|
||||
showUpgradeDialog = {}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun getDonateAlertDialogState() =
|
||||
rememberAlertDialogState().apply {
|
||||
DialogMember {
|
||||
DonateAlertDialog(alertDialogState = this)
|
||||
}
|
||||
}
|
||||
|
||||
stroboscope_btn.setOnClickListener {
|
||||
toggleStroboscope(false)
|
||||
@Composable
|
||||
private fun getRateStarsAlertDialogState() = rememberAlertDialogState().apply {
|
||||
DialogMember {
|
||||
RateStarsAlertDialog(alertDialogState = this, onRating = ::rateStarsRedirectAndThankYou)
|
||||
}
|
||||
}
|
||||
|
||||
setupStroboscope()
|
||||
checkAppOnSDCard()
|
||||
@Composable
|
||||
private fun getSleepTimerCustomDialogState() = rememberAlertDialogState().apply {
|
||||
DialogMember {
|
||||
SleepTimerCustomAlertDialog(
|
||||
alertDialogState = this,
|
||||
onConfirmClick = {
|
||||
if (it > 0) {
|
||||
pickedSleepTimer(it)
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun getSleepTimerDialogState(
|
||||
showCustomSleepTimerDialog: () -> Unit
|
||||
) = rememberAlertDialogState().apply {
|
||||
DialogMember {
|
||||
SleepTimerRadioDialog(
|
||||
alertDialogState = this,
|
||||
onCustomValueSelected = showCustomSleepTimerDialog
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun getSleepTimerPermissionDialogState(
|
||||
showSleepTimerDialog: () -> Unit
|
||||
) = rememberAlertDialogState().apply {
|
||||
DialogMember {
|
||||
PermissionRequiredAlertDialog(
|
||||
alertDialogState = this,
|
||||
text = stringResource(id = com.simplemobiletools.commons.R.string.allow_alarm_sleep_timer),
|
||||
positiveActionCallback = {
|
||||
openRequestExactAlarmSettings(baseConfig.appId)
|
||||
},
|
||||
negativeActionCallback = showSleepTimerDialog
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
setupToolbar(main_toolbar)
|
||||
mCameraImpl!!.handleCameraSetup()
|
||||
checkState(MyCameraImpl.isFlashlightOn)
|
||||
viewModel.onResume()
|
||||
|
||||
val contrastColor = getContrastColor()
|
||||
changeIconColor(contrastColor, bright_display_btn)
|
||||
bright_display_btn.beVisibleIf(config.brightDisplay)
|
||||
sos_btn.beVisibleIf(config.sos)
|
||||
|
||||
if (sos_btn.currentTextColor != getProperPrimaryColor()) {
|
||||
sos_btn.setTextColor(contrastColor)
|
||||
}
|
||||
|
||||
stroboscope_btn.beVisibleIf(config.stroboscope)
|
||||
|
||||
if (!config.stroboscope) {
|
||||
mCameraImpl!!.stopStroboscope()
|
||||
stroboscope_bar.beInvisible()
|
||||
}
|
||||
|
||||
updateTextColors(main_holder)
|
||||
if (stroboscope_bar.isInvisible()) {
|
||||
changeIconColor(contrastColor, stroboscope_btn)
|
||||
}
|
||||
|
||||
requestedOrientation = if (config.forcePortraitMode) ActivityInfo.SCREEN_ORIENTATION_PORTRAIT else ActivityInfo.SCREEN_ORIENTATION_SENSOR
|
||||
requestedOrientation = if (preferences.forcePortraitMode) ActivityInfo.SCREEN_ORIENTATION_PORTRAIT else ActivityInfo.SCREEN_ORIENTATION_SENSOR
|
||||
invalidateOptionsMenu()
|
||||
|
||||
if (config.turnFlashlightOn && reTurnFlashlightOn) {
|
||||
mCameraImpl!!.enableFlashlight()
|
||||
}
|
||||
|
||||
reTurnFlashlightOn = true
|
||||
|
||||
checkShortcuts()
|
||||
}
|
||||
|
||||
override fun onStart() {
|
||||
super.onStart()
|
||||
mBus!!.register(this)
|
||||
|
||||
if (mCameraImpl == null) {
|
||||
setupCameraImpl()
|
||||
}
|
||||
}
|
||||
|
||||
override fun onStop() {
|
||||
super.onStop()
|
||||
mBus!!.unregister(this)
|
||||
}
|
||||
|
||||
override fun onDestroy() {
|
||||
super.onDestroy()
|
||||
releaseCamera()
|
||||
}
|
||||
|
||||
private fun setupOptionsMenu() {
|
||||
main_toolbar.setOnMenuItemClickListener { menuItem ->
|
||||
when (menuItem.itemId) {
|
||||
R.id.settings -> launchSettings()
|
||||
R.id.about -> launchAbout()
|
||||
else -> return@setOnMenuItemClickListener false
|
||||
}
|
||||
return@setOnMenuItemClickListener true
|
||||
}
|
||||
}
|
||||
|
||||
override fun onSaveInstanceState(outState: Bundle) {
|
||||
outState.putBoolean(FLASHLIGHT_STATE, mIsFlashlightOn)
|
||||
outState.putBoolean(STROBOSCOPE_STATE, stroboscope_bar.isVisible())
|
||||
super.onSaveInstanceState(outState)
|
||||
}
|
||||
|
||||
override fun onRestoreInstanceState(savedInstanceState: Bundle) {
|
||||
super.onRestoreInstanceState(savedInstanceState)
|
||||
val isFlashlightOn = savedInstanceState.getBoolean(FLASHLIGHT_STATE, false)
|
||||
if (isFlashlightOn) {
|
||||
mCameraImpl!!.toggleFlashlight()
|
||||
}
|
||||
|
||||
val isStroboscopeOn = savedInstanceState.getBoolean(STROBOSCOPE_STATE, false)
|
||||
if (isStroboscopeOn) {
|
||||
toggleStroboscope(false)
|
||||
if (preferences.sleepInTS == 0L) {
|
||||
viewModel.hideTimer()
|
||||
(getSystemService(Context.ALARM_SERVICE) as AlarmManager).cancel(getShutDownPendingIntent())
|
||||
}
|
||||
}
|
||||
|
||||
private fun launchSettings() {
|
||||
hideKeyboard()
|
||||
reTurnFlashlightOn = false
|
||||
startActivity(Intent(applicationContext, SettingsActivity::class.java))
|
||||
}
|
||||
|
||||
private fun launchAbout() {
|
||||
reTurnFlashlightOn = false
|
||||
val licenses = LICENSE_EVENT_BUS
|
||||
|
||||
val faqItems = arrayListOf(
|
||||
FAQItem(R.string.faq_1_title_commons, R.string.faq_1_text_commons),
|
||||
FAQItem(R.string.faq_4_title_commons, R.string.faq_4_text_commons)
|
||||
FAQItem(com.simplemobiletools.commons.R.string.faq_1_title_commons, com.simplemobiletools.commons.R.string.faq_1_text_commons),
|
||||
FAQItem(com.simplemobiletools.commons.R.string.faq_4_title_commons, com.simplemobiletools.commons.R.string.faq_4_text_commons)
|
||||
)
|
||||
|
||||
if (!resources.getBoolean(R.bool.hide_google_relations)) {
|
||||
faqItems.add(FAQItem(R.string.faq_2_title_commons, R.string.faq_2_text_commons))
|
||||
faqItems.add(FAQItem(R.string.faq_6_title_commons, R.string.faq_6_text_commons))
|
||||
if (!resources.getBoolean(com.simplemobiletools.commons.R.bool.hide_google_relations)) {
|
||||
faqItems.add(FAQItem(com.simplemobiletools.commons.R.string.faq_2_title_commons, com.simplemobiletools.commons.R.string.faq_2_text_commons))
|
||||
faqItems.add(FAQItem(com.simplemobiletools.commons.R.string.faq_6_title_commons, com.simplemobiletools.commons.R.string.faq_6_text_commons))
|
||||
}
|
||||
|
||||
startAboutActivity(R.string.app_name, licenses, BuildConfig.VERSION_NAME, faqItems, true)
|
||||
startAboutActivity(R.string.app_name, 0, BuildConfig.VERSION_NAME, faqItems, true)
|
||||
}
|
||||
|
||||
private fun setupCameraImpl() {
|
||||
mCameraImpl = MyCameraImpl.newInstance(this)
|
||||
if (config.turnFlashlightOn) {
|
||||
mCameraImpl!!.enableFlashlight()
|
||||
}
|
||||
}
|
||||
|
||||
private fun setupStroboscope() {
|
||||
stroboscope_bar.max = (MAX_STROBO_DELAY - MIN_STROBO_DELAY).toInt()
|
||||
stroboscope_bar.progress = config.stroboscopeProgress
|
||||
stroboscope_bar.onSeekBarChangeListener { progress ->
|
||||
val frequency = stroboscope_bar.max - progress + MIN_STROBO_DELAY
|
||||
mCameraImpl?.stroboFrequency = frequency
|
||||
config.stroboscopeFrequency = frequency
|
||||
config.stroboscopeProgress = progress
|
||||
}
|
||||
}
|
||||
|
||||
private fun toggleStroboscope(isSOS: Boolean) {
|
||||
private fun toggleStroboscope(isSOS: Boolean, launcher: ManagedActivityResultLauncher<String, Boolean>) {
|
||||
// use the old Camera API for stroboscope, the new Camera Manager is way too slow
|
||||
if (isNougatPlus()) {
|
||||
cameraPermissionGranted(isSOS)
|
||||
} else {
|
||||
handlePermission(PERMISSION_CAMERA) {
|
||||
if (it) {
|
||||
cameraPermissionGranted(isSOS)
|
||||
} else {
|
||||
toast(R.string.camera_permission)
|
||||
}
|
||||
val permission = Manifest.permission.CAMERA
|
||||
if (ContextCompat.checkSelfPermission(this, permission) == PackageManager.PERMISSION_GRANTED) {
|
||||
cameraPermissionGranted(isSOS)
|
||||
} else {
|
||||
launcher.launch(permission)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun getPermissionResultHandler(isSos: Boolean): (Boolean) -> Unit = { granted ->
|
||||
if (granted) {
|
||||
cameraPermissionGranted(isSos)
|
||||
} else {
|
||||
toast(R.string.camera_permission)
|
||||
}
|
||||
}
|
||||
|
||||
private fun cameraPermissionGranted(isSOS: Boolean) {
|
||||
if (isSOS) {
|
||||
val isSOSRunning = mCameraImpl!!.toggleSOS()
|
||||
sos_btn.setTextColor(if (isSOSRunning) getProperPrimaryColor() else getContrastColor())
|
||||
} else if (mCameraImpl!!.toggleStroboscope()) {
|
||||
stroboscope_bar.beInvisibleIf(stroboscope_bar.isVisible())
|
||||
changeIconColor(if (stroboscope_bar.isVisible()) getProperPrimaryColor() else getContrastColor(), stroboscope_btn)
|
||||
}
|
||||
}
|
||||
|
||||
private fun getContrastColor() = getProperBackgroundColor().getContrastColor()
|
||||
|
||||
private fun releaseCamera() {
|
||||
mCameraImpl?.releaseCamera()
|
||||
mCameraImpl = null
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
fun stateChangedEvent(event: Events.StateChanged) {
|
||||
checkState(event.isEnabled)
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
fun stopStroboscope(event: Events.StopStroboscope) {
|
||||
stroboscope_bar.beInvisible()
|
||||
changeIconColor(getContrastColor(), stroboscope_btn)
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
fun stopSOS(event: Events.StopSOS) {
|
||||
sos_btn.setTextColor(getContrastColor())
|
||||
}
|
||||
|
||||
private fun checkState(isEnabled: Boolean) {
|
||||
if (isEnabled) {
|
||||
enableFlashlight()
|
||||
viewModel.enableSos()
|
||||
} else {
|
||||
disableFlashlight()
|
||||
viewModel.enableStroboscope()
|
||||
}
|
||||
}
|
||||
|
||||
private fun enableFlashlight() {
|
||||
changeIconColor(getProperPrimaryColor(), flashlight_btn)
|
||||
window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
|
||||
mIsFlashlightOn = true
|
||||
|
||||
sos_btn.setTextColor(getContrastColor())
|
||||
|
||||
changeIconColor(getContrastColor(), stroboscope_btn)
|
||||
stroboscope_bar.beInvisible()
|
||||
private fun showSleepTimerPermission(
|
||||
requestAlarmPermission: () -> Unit,
|
||||
onNoPermissionRequired: () -> Unit
|
||||
) {
|
||||
val alarmManager = getSystemService(Context.ALARM_SERVICE) as AlarmManager
|
||||
if (isSPlus() && !alarmManager.canScheduleExactAlarms()) {
|
||||
requestAlarmPermission()
|
||||
return
|
||||
}
|
||||
onNoPermissionRequired()
|
||||
}
|
||||
|
||||
private fun disableFlashlight() {
|
||||
changeIconColor(getContrastColor(), flashlight_btn)
|
||||
window.clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
|
||||
mIsFlashlightOn = false
|
||||
private fun secondsToString(seconds: Int): String {
|
||||
val finalHours = seconds / 3600
|
||||
val finalMinutes = (seconds / 60) % 60
|
||||
val finalSeconds = seconds % 60
|
||||
return buildList {
|
||||
if (finalHours != 0) {
|
||||
add(resources.getQuantityString(com.simplemobiletools.commons.R.plurals.hours, finalHours, finalHours))
|
||||
}
|
||||
if (finalMinutes != 0) {
|
||||
add(resources.getQuantityString(com.simplemobiletools.commons.R.plurals.minutes, finalMinutes, finalMinutes))
|
||||
}
|
||||
if (finalSeconds != 0) {
|
||||
add(resources.getQuantityString(com.simplemobiletools.commons.R.plurals.seconds, finalSeconds, finalSeconds))
|
||||
}
|
||||
}.joinToString(separator = " ")
|
||||
}
|
||||
|
||||
private fun changeIconColor(color: Int, imageView: ImageView?) {
|
||||
imageView!!.background.mutate().applyColorFilter(color)
|
||||
private fun pickedSleepTimer(seconds: Int) {
|
||||
preferences.lastSleepTimerSeconds = seconds
|
||||
preferences.sleepInTS = System.currentTimeMillis() + seconds * 1000
|
||||
startSleepTimer()
|
||||
}
|
||||
|
||||
private fun startSleepTimer() {
|
||||
viewModel.showTimer()
|
||||
startSleepTimerCountDown()
|
||||
}
|
||||
|
||||
private fun stopSleepTimer() {
|
||||
viewModel.hideTimer()
|
||||
stopSleepTimerCountDown()
|
||||
}
|
||||
|
||||
@SuppressLint("NewApi")
|
||||
private fun checkShortcuts() {
|
||||
val appIconColor = config.appIconColor
|
||||
if (isNougatMR1Plus() && config.lastHandledShortcutColor != appIconColor) {
|
||||
val appIconColor = preferences.appIconColor
|
||||
if (isNougatMR1Plus() && preferences.lastHandledShortcutColor != appIconColor) {
|
||||
val createNewContact = getBrightDisplayShortcut(appIconColor)
|
||||
|
||||
try {
|
||||
shortcutManager.dynamicShortcuts = Arrays.asList(createNewContact)
|
||||
config.lastHandledShortcutColor = appIconColor
|
||||
shortcutManager.dynamicShortcuts = listOf(createNewContact)
|
||||
preferences.lastHandledShortcutColor = appIconColor
|
||||
} catch (ignored: Exception) {
|
||||
}
|
||||
}
|
||||
|
@ -304,9 +421,147 @@ class MainActivity : SimpleActivity() {
|
|||
.build()
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
fun cameraUnavailable(event: Events.CameraUnavailable) {
|
||||
toast(R.string.camera_error)
|
||||
disableFlashlight()
|
||||
internal class MainViewModel(
|
||||
application: Application
|
||||
) : AndroidViewModel(application) {
|
||||
|
||||
private val preferences = application.config
|
||||
|
||||
private lateinit var camera: MyCameraImpl
|
||||
|
||||
init {
|
||||
camera = MyCameraImpl.newInstance(application, object : CameraTorchListener {
|
||||
override fun onTorchEnabled(isEnabled: Boolean) {
|
||||
camera.onTorchEnabled(isEnabled)
|
||||
if (isEnabled && camera.supportsBrightnessControl()) {
|
||||
_brightnessBarValue.value = camera.getCurrentBrightnessLevel().toFloat() / camera.getMaximumBrightnessLevel()
|
||||
}
|
||||
}
|
||||
|
||||
override fun onTorchUnavailable() {
|
||||
camera.onCameraNotAvailable()
|
||||
}
|
||||
})
|
||||
if (preferences.turnFlashlightOn) {
|
||||
camera.enableFlashlight()
|
||||
}
|
||||
}
|
||||
|
||||
private val _timerText: MutableStateFlow<String> = MutableStateFlow("00:00")
|
||||
val timerText = _timerText.asStateFlow()
|
||||
|
||||
private val _timerVisible: MutableStateFlow<Boolean> = MutableStateFlow(false)
|
||||
val timerVisible = _timerVisible.asStateFlow()
|
||||
|
||||
val flashlightOn = camera.flashlightOnFlow
|
||||
|
||||
val brightnessBarVisible = flashlightOn.map {
|
||||
it && camera.supportsBrightnessControl()
|
||||
}.stateIn(viewModelScope, SharingStarted.Lazily, false)
|
||||
|
||||
private val _sosActive: MutableStateFlow<Boolean> = MutableStateFlow(false)
|
||||
val sosActive = _sosActive.asStateFlow()
|
||||
|
||||
private val _brightnessBarValue: MutableStateFlow<Float> = MutableStateFlow(1f)
|
||||
val brightnessBarValue = _brightnessBarValue.asStateFlow()
|
||||
|
||||
private val _stroboscopeActive: MutableStateFlow<Boolean> = MutableStateFlow(false)
|
||||
val stroboscopeActive = _stroboscopeActive.asStateFlow()
|
||||
|
||||
val stroboscopeBarVisible = stroboscopeActive
|
||||
|
||||
private val _stroboscopeBarValue: MutableStateFlow<Float> = MutableStateFlow(0.5f)
|
||||
val stroboscopeBarValue = _stroboscopeBarValue.asStateFlow()
|
||||
|
||||
init {
|
||||
_stroboscopeBarValue.value = preferences.stroboscopeProgress.toFloat() / MAX_STROBO_DELAY
|
||||
|
||||
SleepTimer.timeLeft
|
||||
.onEach { seconds ->
|
||||
_timerText.value = seconds.getFormattedDuration()
|
||||
_timerVisible.value = true
|
||||
|
||||
if (seconds == 0) {
|
||||
exitProcess(0)
|
||||
}
|
||||
}
|
||||
.launchIn(viewModelScope)
|
||||
|
||||
MyCameraImpl.cameraError
|
||||
.onEach { getApplication<Application>().toast(R.string.camera_error) }
|
||||
.launchIn(viewModelScope)
|
||||
|
||||
camera.stroboscopeDisabled
|
||||
.onEach { _stroboscopeActive.value = false }
|
||||
.launchIn(viewModelScope)
|
||||
|
||||
camera.sosDisabled
|
||||
.onEach { _sosActive.value = false }
|
||||
.launchIn(viewModelScope)
|
||||
}
|
||||
|
||||
fun hideTimer() {
|
||||
_timerVisible.value = false
|
||||
}
|
||||
|
||||
fun showTimer() {
|
||||
_timerVisible.value = true
|
||||
}
|
||||
|
||||
fun updateBrightnessBarValue(newValue: Float) {
|
||||
_brightnessBarValue.value = newValue
|
||||
val max = camera.getMaximumBrightnessLevel()
|
||||
val min = MIN_BRIGHTNESS_LEVEL
|
||||
val newLevel = MathUtils.lerp(min.toFloat(), max.toFloat(), newValue)
|
||||
camera.updateBrightnessLevel(newLevel.toInt())
|
||||
preferences.brightnessLevel = newLevel.toInt()
|
||||
}
|
||||
|
||||
fun updateStroboscopeBarValue(newValue: Float) {
|
||||
_stroboscopeBarValue.value = newValue
|
||||
val max = MAX_STROBO_DELAY
|
||||
val min = MIN_STROBO_DELAY
|
||||
val newLevel = MathUtils.lerp(min.toFloat(), max.toFloat(), 1 - newValue)
|
||||
camera.stroboFrequency = newLevel.toLong()
|
||||
preferences.stroboscopeFrequency = newLevel.toLong()
|
||||
preferences.stroboscopeProgress = ((1 - newLevel) * MAX_STROBO_DELAY).toInt()
|
||||
}
|
||||
|
||||
fun onResume() {
|
||||
camera.handleCameraSetup()
|
||||
|
||||
if (preferences.turnFlashlightOn) {
|
||||
camera.enableFlashlight()
|
||||
}
|
||||
|
||||
if (!preferences.stroboscope && _stroboscopeActive.value) {
|
||||
camera.stopStroboscope()
|
||||
}
|
||||
|
||||
if (!preferences.sos && _sosActive.value) {
|
||||
camera.stopSOS()
|
||||
}
|
||||
}
|
||||
|
||||
override fun onCleared() {
|
||||
super.onCleared()
|
||||
releaseCamera()
|
||||
}
|
||||
|
||||
fun toggleFlashlight() {
|
||||
camera.toggleFlashlight()
|
||||
}
|
||||
|
||||
private fun releaseCamera() {
|
||||
camera.releaseCamera()
|
||||
}
|
||||
|
||||
fun enableSos() {
|
||||
_sosActive.value = camera.toggleSOS()
|
||||
}
|
||||
|
||||
fun enableStroboscope() {
|
||||
_stroboscopeActive.value = camera.toggleStroboscope()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,136 +2,95 @@ package com.simplemobiletools.flashlight.activities
|
|||
|
||||
import android.content.Intent
|
||||
import android.os.Bundle
|
||||
import com.simplemobiletools.commons.extensions.*
|
||||
import androidx.activity.ComponentActivity
|
||||
import androidx.activity.compose.setContent
|
||||
import androidx.compose.runtime.derivedStateOf
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import com.simplemobiletools.commons.compose.extensions.enableEdgeToEdgeSimple
|
||||
import com.simplemobiletools.commons.compose.theme.AppThemeSurface
|
||||
import com.simplemobiletools.commons.helpers.IS_CUSTOMIZING_COLORS
|
||||
import com.simplemobiletools.commons.helpers.NavigationIcon
|
||||
import com.simplemobiletools.commons.helpers.isTiramisuPlus
|
||||
import com.simplemobiletools.flashlight.R
|
||||
import com.simplemobiletools.flashlight.extensions.config
|
||||
import kotlinx.android.synthetic.main.activity_settings.*
|
||||
import java.util.*
|
||||
import com.simplemobiletools.flashlight.extensions.launchChangeAppLanguageIntent
|
||||
import com.simplemobiletools.flashlight.extensions.startCustomizationActivity
|
||||
import com.simplemobiletools.flashlight.screens.ColorCustomizationSettingsSection
|
||||
import com.simplemobiletools.flashlight.screens.GeneralSettingsSection
|
||||
import com.simplemobiletools.flashlight.screens.SettingsScreen
|
||||
import java.util.Locale
|
||||
import kotlin.system.exitProcess
|
||||
|
||||
class SettingsActivity : SimpleActivity() {
|
||||
class SettingsActivity : ComponentActivity() {
|
||||
private val preferences by lazy { config }
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
setContentView(R.layout.activity_settings)
|
||||
}
|
||||
enableEdgeToEdgeSimple()
|
||||
setContent {
|
||||
AppThemeSurface {
|
||||
SettingsScreen(
|
||||
colorCustomizationSection = {
|
||||
ColorCustomizationSettingsSection(
|
||||
customizeColors = ::startCustomizationActivity,
|
||||
customizeWidgetColors = {
|
||||
Intent(this, WidgetTorchConfigureActivity::class.java).apply {
|
||||
putExtra(IS_CUSTOMIZING_COLORS, true)
|
||||
startActivity(this)
|
||||
}
|
||||
}
|
||||
)
|
||||
},
|
||||
generalSection = {
|
||||
val displayLanguage = remember { Locale.getDefault().displayLanguage }
|
||||
val useEnglishChecked by preferences.useEnglishFlow.collectAsStateWithLifecycle(preferences.useEnglish)
|
||||
val wasUseEnglishToggled by preferences.wasUseEnglishToggledFlow.collectAsStateWithLifecycle(preferences.wasUseEnglishToggled)
|
||||
val showUseEnglish by remember {
|
||||
derivedStateOf {
|
||||
(wasUseEnglishToggled || Locale.getDefault().language != "en") && !isTiramisuPlus()
|
||||
}
|
||||
}
|
||||
val turnFlashlightOnStartupFlow by preferences.turnFlashlightOnFlow.collectAsStateWithLifecycle(preferences.turnFlashlightOn)
|
||||
val forcePortraitModeFlow by preferences.forcePortraitModeFlow.collectAsStateWithLifecycle(preferences.forcePortraitMode)
|
||||
val showBrightDisplayButtonFlow by preferences.brightDisplayFlow.collectAsStateWithLifecycle(preferences.brightDisplay)
|
||||
val showSosButtonFlow by preferences.sosFlow.collectAsStateWithLifecycle(preferences.sos)
|
||||
val showStroboscopeButtonFlow by preferences.stroboscopeFlow.collectAsStateWithLifecycle(preferences.stroboscope)
|
||||
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
setupToolbar(settings_toolbar, NavigationIcon.Arrow)
|
||||
|
||||
setupPurchaseThankYou()
|
||||
setupCustomizeColors()
|
||||
setupCustomizeWidgetColors()
|
||||
setupUseEnglish()
|
||||
setupLanguage()
|
||||
setupTurnFlashlightOn()
|
||||
setupBrightDisplay()
|
||||
setupStroboscope()
|
||||
setupSOS()
|
||||
setupForcePortrait()
|
||||
updateTextColors(settings_holder)
|
||||
|
||||
arrayOf(settings_color_customization_label, settings_general_settings_label).forEach {
|
||||
it.setTextColor(getProperPrimaryColor())
|
||||
}
|
||||
|
||||
arrayOf(settings_color_customization_holder, settings_general_settings_holder).forEach {
|
||||
it.background.applyColorFilter(getProperBackgroundColor().getContrastColor())
|
||||
}
|
||||
}
|
||||
|
||||
private fun setupPurchaseThankYou() {
|
||||
settings_purchase_thank_you_holder.beGoneIf(isOrWasThankYouInstalled())
|
||||
|
||||
// make sure the corners at ripple fit the stroke rounded corners
|
||||
if (settings_purchase_thank_you_holder.isGone()) {
|
||||
settings_use_english_holder.background = resources.getDrawable(R.drawable.ripple_top_corners, theme)
|
||||
}
|
||||
|
||||
settings_purchase_thank_you_holder.setOnClickListener {
|
||||
launchPurchaseThankYouIntent()
|
||||
}
|
||||
}
|
||||
|
||||
private fun setupCustomizeColors() {
|
||||
settings_customize_colors_label.text = getCustomizeColorsString()
|
||||
settings_customize_colors_holder.setOnClickListener {
|
||||
handleCustomizeColorsClick()
|
||||
}
|
||||
}
|
||||
|
||||
private fun setupCustomizeWidgetColors() {
|
||||
settings_customize_widget_colors_holder.setOnClickListener {
|
||||
Intent(this, WidgetTorchConfigureActivity::class.java).apply {
|
||||
putExtra(IS_CUSTOMIZING_COLORS, true)
|
||||
startActivity(this)
|
||||
GeneralSettingsSection(
|
||||
showUseEnglish = showUseEnglish,
|
||||
useEnglishChecked = useEnglishChecked,
|
||||
showDisplayLanguage = isTiramisuPlus(),
|
||||
displayLanguage = displayLanguage,
|
||||
onUseEnglishPress = {
|
||||
config.useEnglish = it
|
||||
exitProcess(0)
|
||||
},
|
||||
onSetupLanguagePress = ::launchChangeAppLanguageIntent,
|
||||
turnFlashlightOnStartupChecked = turnFlashlightOnStartupFlow,
|
||||
forcePortraitModeChecked = forcePortraitModeFlow,
|
||||
showBrightDisplayButtonChecked = showBrightDisplayButtonFlow,
|
||||
showSosButtonChecked = showSosButtonFlow,
|
||||
showStroboscopeButtonChecked = showStroboscopeButtonFlow,
|
||||
onTurnFlashlightOnStartupPress = {
|
||||
preferences.turnFlashlightOn = it
|
||||
},
|
||||
onForcePortraitModePress = {
|
||||
preferences.forcePortraitMode = it
|
||||
},
|
||||
onShowBrightDisplayButtonPress = {
|
||||
preferences.brightDisplay = it
|
||||
},
|
||||
onShowSosButtonPress = {
|
||||
preferences.sos = it
|
||||
},
|
||||
onShowStroboscopeButtonPress = {
|
||||
preferences.stroboscope = it
|
||||
},
|
||||
)
|
||||
},
|
||||
goBack = ::finish
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun setupUseEnglish() {
|
||||
settings_use_english_holder.beVisibleIf((config.wasUseEnglishToggled || Locale.getDefault().language != "en") && !isTiramisuPlus())
|
||||
settings_use_english.isChecked = config.useEnglish
|
||||
settings_use_english_holder.setOnClickListener {
|
||||
settings_use_english.toggle()
|
||||
config.useEnglish = settings_use_english.isChecked
|
||||
exitProcess(0)
|
||||
}
|
||||
}
|
||||
|
||||
private fun setupLanguage() {
|
||||
settings_language.text = Locale.getDefault().displayLanguage
|
||||
settings_language_holder.beVisibleIf(isTiramisuPlus())
|
||||
|
||||
if (settings_use_english_holder.isGone() && settings_language_holder.isGone() && settings_purchase_thank_you_holder.isGone()) {
|
||||
settings_turn_flashlight_on_holder.background = resources.getDrawable(R.drawable.ripple_top_corners, theme)
|
||||
}
|
||||
|
||||
settings_language_holder.setOnClickListener {
|
||||
launchChangeAppLanguageIntent()
|
||||
}
|
||||
}
|
||||
|
||||
private fun setupTurnFlashlightOn() {
|
||||
settings_turn_flashlight_on.isChecked = config.turnFlashlightOn
|
||||
settings_turn_flashlight_on_holder.setOnClickListener {
|
||||
settings_turn_flashlight_on.toggle()
|
||||
config.turnFlashlightOn = settings_turn_flashlight_on.isChecked
|
||||
}
|
||||
}
|
||||
|
||||
private fun setupBrightDisplay() {
|
||||
settings_bright_display.isChecked = config.brightDisplay
|
||||
settings_bright_display_holder.setOnClickListener {
|
||||
settings_bright_display.toggle()
|
||||
config.brightDisplay = settings_bright_display.isChecked
|
||||
}
|
||||
}
|
||||
|
||||
private fun setupStroboscope() {
|
||||
settings_stroboscope.isChecked = config.stroboscope
|
||||
settings_stroboscope_holder.setOnClickListener {
|
||||
settings_stroboscope.toggle()
|
||||
config.stroboscope = settings_stroboscope.isChecked
|
||||
}
|
||||
}
|
||||
|
||||
private fun setupSOS() {
|
||||
settings_sos.isChecked = config.sos
|
||||
settings_sos_holder.setOnClickListener {
|
||||
settings_sos.toggle()
|
||||
config.sos = settings_sos.isChecked
|
||||
}
|
||||
}
|
||||
|
||||
private fun setupForcePortrait() {
|
||||
settings_force_portrait.isChecked = config.forcePortraitMode
|
||||
settings_force_portrait_holder.setOnClickListener {
|
||||
settings_force_portrait.toggle()
|
||||
config.forcePortraitMode = settings_force_portrait.isChecked
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,119 +3,115 @@ package com.simplemobiletools.flashlight.activities
|
|||
import android.app.Activity
|
||||
import android.appwidget.AppWidgetManager
|
||||
import android.content.Intent
|
||||
import android.content.res.ColorStateList
|
||||
import android.graphics.Color
|
||||
import android.os.Bundle
|
||||
import android.widget.SeekBar
|
||||
import com.simplemobiletools.commons.dialogs.ColorPickerDialog
|
||||
import com.simplemobiletools.commons.dialogs.FeatureLockedDialog
|
||||
import com.simplemobiletools.commons.extensions.*
|
||||
import androidx.activity.ComponentActivity
|
||||
import androidx.activity.compose.setContent
|
||||
import androidx.activity.viewModels
|
||||
import androidx.annotation.ColorInt
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.DisposableEffect
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import com.simplemobiletools.commons.compose.alert_dialog.rememberAlertDialogState
|
||||
import com.simplemobiletools.commons.compose.extensions.enableEdgeToEdgeSimple
|
||||
import com.simplemobiletools.commons.compose.system_ui_controller.rememberSystemUiController
|
||||
import com.simplemobiletools.commons.compose.theme.AppTheme
|
||||
import com.simplemobiletools.commons.compose.theme.SimpleTheme
|
||||
import com.simplemobiletools.commons.compose.theme.isLitWell
|
||||
import com.simplemobiletools.commons.dialogs.ColorPickerAlertDialog
|
||||
import com.simplemobiletools.commons.extensions.isUsingSystemDarkTheme
|
||||
import com.simplemobiletools.commons.helpers.IS_CUSTOMIZING_COLORS
|
||||
import com.simplemobiletools.flashlight.R
|
||||
import com.simplemobiletools.flashlight.activities.viewmodel.WidgetConfigureViewModel
|
||||
import com.simplemobiletools.flashlight.extensions.CheckFeatureLocked
|
||||
import com.simplemobiletools.flashlight.extensions.config
|
||||
import com.simplemobiletools.flashlight.helpers.MyWidgetBrightDisplayProvider
|
||||
import kotlinx.android.synthetic.main.widget_bright_display_config.*
|
||||
import com.simplemobiletools.flashlight.screens.WidgetConfigureScreen
|
||||
|
||||
class WidgetBrightDisplayConfigureActivity : SimpleActivity() {
|
||||
private var mWidgetAlpha = 0f
|
||||
private var mWidgetId = 0
|
||||
private var mWidgetColor = 0
|
||||
private var mWidgetColorWithoutTransparency = 0
|
||||
private var mFeatureLockedDialog: FeatureLockedDialog? = null
|
||||
class WidgetBrightDisplayConfigureActivity : ComponentActivity() {
|
||||
private val viewModel by viewModels<WidgetConfigureViewModel>()
|
||||
|
||||
public override fun onCreate(savedInstanceState: Bundle?) {
|
||||
useDynamicTheme = false
|
||||
super.onCreate(savedInstanceState)
|
||||
setResult(Activity.RESULT_CANCELED)
|
||||
setContentView(R.layout.widget_bright_display_config)
|
||||
initVariables()
|
||||
|
||||
val isCustomizingColors = intent.extras?.getBoolean(IS_CUSTOMIZING_COLORS) ?: false
|
||||
mWidgetId = intent.extras?.getInt(AppWidgetManager.EXTRA_APPWIDGET_ID) ?: AppWidgetManager.INVALID_APPWIDGET_ID
|
||||
viewModel.setWidgetId(intent.extras?.getInt(AppWidgetManager.EXTRA_APPWIDGET_ID) ?: AppWidgetManager.INVALID_APPWIDGET_ID)
|
||||
|
||||
if (mWidgetId == AppWidgetManager.INVALID_APPWIDGET_ID && !isCustomizingColors) {
|
||||
if (viewModel.widgetId.value == AppWidgetManager.INVALID_APPWIDGET_ID && !isCustomizingColors) {
|
||||
finish()
|
||||
}
|
||||
|
||||
config_save.setOnClickListener { saveConfig() }
|
||||
config_widget_color.setOnClickListener { pickBackgroundColor() }
|
||||
setContent {
|
||||
AppTheme {
|
||||
|
||||
val primaryColor = getProperPrimaryColor()
|
||||
config_widget_seekbar.setColors(getProperTextColor(), primaryColor, primaryColor)
|
||||
val systemUiController = rememberSystemUiController()
|
||||
val surfaceColor = SimpleTheme.colorScheme.surface
|
||||
|
||||
if (!isCustomizingColors && !isOrWasThankYouInstalled()) {
|
||||
mFeatureLockedDialog = FeatureLockedDialog(this) {
|
||||
if (!isOrWasThankYouInstalled()) {
|
||||
finish()
|
||||
DisposableEffect(systemUiController, !isUsingSystemDarkTheme(), surfaceColor) {
|
||||
systemUiController.setSystemBarsColor(
|
||||
color = surfaceColor,
|
||||
darkIcons = surfaceColor.isLitWell()
|
||||
)
|
||||
onDispose { }
|
||||
}
|
||||
|
||||
val widgetColor by viewModel.widgetColor.collectAsStateWithLifecycle()
|
||||
val widgetAlpha by viewModel.widgetAlpha.collectAsStateWithLifecycle()
|
||||
|
||||
val colorPickerDialogState = getColorPickerDialogState(widgetColor)
|
||||
|
||||
WidgetConfigureScreen(
|
||||
widgetDrawable = R.drawable.ic_bright_display_vector,
|
||||
widgetColor = widgetColor,
|
||||
widgetAlpha = widgetAlpha,
|
||||
onSliderChanged = viewModel::changeAlpha,
|
||||
onColorPressed = colorPickerDialogState::show,
|
||||
onSavePressed = ::saveConfig
|
||||
)
|
||||
|
||||
|
||||
CheckFeatureLocked(skipCheck = isCustomizingColors)
|
||||
}
|
||||
}
|
||||
|
||||
config_save.backgroundTintList = ColorStateList.valueOf(getProperPrimaryColor())
|
||||
config_save.setTextColor(getProperPrimaryColor().getContrastColor())
|
||||
}
|
||||
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
window.decorView.setBackgroundColor(0)
|
||||
setupToolbar(config_bright_display_toolbar)
|
||||
|
||||
if (mFeatureLockedDialog != null && isOrWasThankYouInstalled()) {
|
||||
mFeatureLockedDialog?.dismissDialog()
|
||||
@Composable
|
||||
private fun getColorPickerDialogState(
|
||||
@ColorInt
|
||||
widgetColor: Int
|
||||
) = rememberAlertDialogState().apply {
|
||||
DialogMember {
|
||||
ColorPickerAlertDialog(
|
||||
alertDialogState = this,
|
||||
color = widgetColor,
|
||||
removeDimmedBackground = true,
|
||||
onActiveColorChange = {},
|
||||
onButtonPressed = { wasPositivePressed, color ->
|
||||
if (wasPositivePressed) {
|
||||
viewModel.updateColor(color)
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun initVariables() {
|
||||
mWidgetColor = config.widgetBgColor
|
||||
mWidgetAlpha = Color.alpha(mWidgetColor) / 255.toFloat()
|
||||
|
||||
mWidgetColorWithoutTransparency = Color.rgb(Color.red(mWidgetColor), Color.green(mWidgetColor), Color.blue(mWidgetColor))
|
||||
config_widget_seekbar.setOnSeekBarChangeListener(seekbarChangeListener)
|
||||
config_widget_seekbar.progress = (mWidgetAlpha * 100).toInt()
|
||||
updateColors()
|
||||
}
|
||||
|
||||
private fun saveConfig() {
|
||||
config.widgetBgColor = mWidgetColor
|
||||
config.widgetBgColor = viewModel.widgetColor.value
|
||||
requestWidgetUpdate()
|
||||
|
||||
Intent().apply {
|
||||
putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, mWidgetId)
|
||||
putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, viewModel.widgetId.value)
|
||||
setResult(Activity.RESULT_OK, this)
|
||||
}
|
||||
finish()
|
||||
}
|
||||
|
||||
private fun pickBackgroundColor() {
|
||||
ColorPickerDialog(this, mWidgetColorWithoutTransparency) { wasPositivePressed, color ->
|
||||
if (wasPositivePressed) {
|
||||
mWidgetColorWithoutTransparency = color
|
||||
updateColors()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun requestWidgetUpdate() {
|
||||
Intent(AppWidgetManager.ACTION_APPWIDGET_UPDATE, null, this, MyWidgetBrightDisplayProvider::class.java).apply {
|
||||
putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, intArrayOf(mWidgetId))
|
||||
putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, intArrayOf(viewModel.widgetId.value))
|
||||
sendBroadcast(this)
|
||||
}
|
||||
}
|
||||
|
||||
private fun updateColors() {
|
||||
mWidgetColor = mWidgetColorWithoutTransparency.adjustAlpha(mWidgetAlpha)
|
||||
config_widget_color.setFillWithStroke(mWidgetColor, mWidgetColor)
|
||||
config_image.background.mutate().applyColorFilter(mWidgetColor)
|
||||
}
|
||||
|
||||
private val seekbarChangeListener = object : SeekBar.OnSeekBarChangeListener {
|
||||
override fun onProgressChanged(seekBar: SeekBar, progress: Int, fromUser: Boolean) {
|
||||
mWidgetAlpha = progress.toFloat() / 100.toFloat()
|
||||
updateColors()
|
||||
}
|
||||
|
||||
override fun onStartTrackingTouch(seekBar: SeekBar) {}
|
||||
|
||||
override fun onStopTrackingTouch(seekBar: SeekBar) {}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,122 +3,116 @@ package com.simplemobiletools.flashlight.activities
|
|||
import android.app.Activity
|
||||
import android.appwidget.AppWidgetManager
|
||||
import android.content.Intent
|
||||
import android.content.res.ColorStateList
|
||||
import android.graphics.Color
|
||||
import android.os.Bundle
|
||||
import android.widget.SeekBar
|
||||
import com.simplemobiletools.commons.dialogs.ColorPickerDialog
|
||||
import com.simplemobiletools.commons.dialogs.FeatureLockedDialog
|
||||
import com.simplemobiletools.commons.extensions.*
|
||||
import androidx.activity.ComponentActivity
|
||||
import androidx.activity.compose.setContent
|
||||
import androidx.activity.viewModels
|
||||
import androidx.annotation.ColorInt
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.DisposableEffect
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import com.simplemobiletools.commons.compose.alert_dialog.rememberAlertDialogState
|
||||
import com.simplemobiletools.commons.compose.extensions.enableEdgeToEdgeSimple
|
||||
import com.simplemobiletools.commons.compose.system_ui_controller.rememberSystemUiController
|
||||
import com.simplemobiletools.commons.compose.theme.AppTheme
|
||||
import com.simplemobiletools.commons.compose.theme.SimpleTheme
|
||||
import com.simplemobiletools.commons.compose.theme.isLitWell
|
||||
import com.simplemobiletools.commons.dialogs.ColorPickerAlertDialog
|
||||
import com.simplemobiletools.commons.extensions.isUsingSystemDarkTheme
|
||||
import com.simplemobiletools.commons.helpers.IS_CUSTOMIZING_COLORS
|
||||
import com.simplemobiletools.flashlight.R
|
||||
import com.simplemobiletools.flashlight.activities.viewmodel.WidgetConfigureViewModel
|
||||
import com.simplemobiletools.flashlight.extensions.CheckFeatureLocked
|
||||
import com.simplemobiletools.flashlight.extensions.config
|
||||
import com.simplemobiletools.flashlight.extensions.updateBrightDisplayWidget
|
||||
import com.simplemobiletools.flashlight.helpers.MyWidgetTorchProvider
|
||||
import kotlinx.android.synthetic.main.widget_torch_config.*
|
||||
import com.simplemobiletools.flashlight.screens.WidgetConfigureScreen
|
||||
|
||||
class WidgetTorchConfigureActivity : SimpleActivity() {
|
||||
private var mWidgetAlpha = 0f
|
||||
private var mWidgetId = 0
|
||||
private var mWidgetColor = 0
|
||||
private var mWidgetColorWithoutTransparency = 0
|
||||
private var mFeatureLockedDialog: FeatureLockedDialog? = null
|
||||
class WidgetTorchConfigureActivity : ComponentActivity() {
|
||||
private val viewModel by viewModels<WidgetConfigureViewModel>()
|
||||
|
||||
public override fun onCreate(savedInstanceState: Bundle?) {
|
||||
useDynamicTheme = false
|
||||
super.onCreate(savedInstanceState)
|
||||
setResult(Activity.RESULT_CANCELED)
|
||||
setContentView(R.layout.widget_torch_config)
|
||||
initVariables()
|
||||
|
||||
val isCustomizingColors = intent.extras?.getBoolean(IS_CUSTOMIZING_COLORS) ?: false
|
||||
mWidgetId = intent.extras?.getInt(AppWidgetManager.EXTRA_APPWIDGET_ID) ?: AppWidgetManager.INVALID_APPWIDGET_ID
|
||||
viewModel.setWidgetId(intent.extras?.getInt(AppWidgetManager.EXTRA_APPWIDGET_ID) ?: AppWidgetManager.INVALID_APPWIDGET_ID)
|
||||
|
||||
if (mWidgetId == AppWidgetManager.INVALID_APPWIDGET_ID && !isCustomizingColors) {
|
||||
if (viewModel.widgetId.value == AppWidgetManager.INVALID_APPWIDGET_ID && !isCustomizingColors) {
|
||||
finish()
|
||||
}
|
||||
|
||||
config_save.setOnClickListener { saveConfig() }
|
||||
config_widget_color.setOnClickListener { pickBackgroundColor() }
|
||||
setContent {
|
||||
AppTheme {
|
||||
|
||||
val primaryColor = getProperPrimaryColor()
|
||||
config_widget_seekbar.setColors(getProperTextColor(), primaryColor, primaryColor)
|
||||
val systemUiController = rememberSystemUiController()
|
||||
val surfaceColor = SimpleTheme.colorScheme.surface
|
||||
|
||||
if (!isCustomizingColors && !isOrWasThankYouInstalled()) {
|
||||
mFeatureLockedDialog = FeatureLockedDialog(this) {
|
||||
if (!isOrWasThankYouInstalled()) {
|
||||
finish()
|
||||
DisposableEffect(systemUiController, !isUsingSystemDarkTheme(), surfaceColor) {
|
||||
systemUiController.setSystemBarsColor(
|
||||
color = surfaceColor,
|
||||
darkIcons = surfaceColor.isLitWell()
|
||||
)
|
||||
onDispose { }
|
||||
}
|
||||
|
||||
val widgetColor by viewModel.widgetColor.collectAsStateWithLifecycle()
|
||||
val widgetAlpha by viewModel.widgetAlpha.collectAsStateWithLifecycle()
|
||||
|
||||
val colorPickerDialogState = getColorPickerDialogState(widgetColor)
|
||||
|
||||
WidgetConfigureScreen(
|
||||
widgetDrawable = R.drawable.ic_flashlight_vector,
|
||||
widgetColor = widgetColor,
|
||||
widgetAlpha = widgetAlpha,
|
||||
onSliderChanged = viewModel::changeAlpha,
|
||||
onColorPressed = colorPickerDialogState::show,
|
||||
onSavePressed = ::saveConfig
|
||||
)
|
||||
|
||||
CheckFeatureLocked(skipCheck = isCustomizingColors)
|
||||
}
|
||||
}
|
||||
|
||||
config_save.backgroundTintList = ColorStateList.valueOf(getProperPrimaryColor())
|
||||
config_save.setTextColor(getProperPrimaryColor().getContrastColor())
|
||||
}
|
||||
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
window.decorView.setBackgroundColor(0)
|
||||
setupToolbar(config_torch_toolbar)
|
||||
|
||||
if (mFeatureLockedDialog != null && isOrWasThankYouInstalled()) {
|
||||
mFeatureLockedDialog?.dismissDialog()
|
||||
@Composable
|
||||
private fun getColorPickerDialogState(
|
||||
@ColorInt
|
||||
widgetColor: Int
|
||||
) = rememberAlertDialogState().apply {
|
||||
DialogMember {
|
||||
ColorPickerAlertDialog(
|
||||
alertDialogState = this,
|
||||
color = widgetColor,
|
||||
removeDimmedBackground = true,
|
||||
onActiveColorChange = {},
|
||||
onButtonPressed = { wasPositivePressed, color ->
|
||||
if (wasPositivePressed) {
|
||||
viewModel.updateColor(color)
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun initVariables() {
|
||||
mWidgetColor = config.widgetBgColor
|
||||
mWidgetAlpha = Color.alpha(mWidgetColor) / 255.toFloat()
|
||||
|
||||
mWidgetColorWithoutTransparency = Color.rgb(Color.red(mWidgetColor), Color.green(mWidgetColor), Color.blue(mWidgetColor))
|
||||
config_widget_seekbar.setOnSeekBarChangeListener(seekbarChangeListener)
|
||||
config_widget_seekbar.progress = (mWidgetAlpha * 100).toInt()
|
||||
updateColors()
|
||||
}
|
||||
|
||||
private fun saveConfig() {
|
||||
config.widgetBgColor = mWidgetColor
|
||||
config.widgetBgColor = viewModel.widgetColor.value
|
||||
requestWidgetUpdate()
|
||||
|
||||
Intent().apply {
|
||||
putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, mWidgetId)
|
||||
putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, viewModel.widgetId.value)
|
||||
setResult(Activity.RESULT_OK, this)
|
||||
}
|
||||
finish()
|
||||
}
|
||||
|
||||
private fun pickBackgroundColor() {
|
||||
ColorPickerDialog(this, mWidgetColorWithoutTransparency) { wasPositivePressed, color ->
|
||||
if (wasPositivePressed) {
|
||||
mWidgetColorWithoutTransparency = color
|
||||
updateColors()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun requestWidgetUpdate() {
|
||||
Intent(AppWidgetManager.ACTION_APPWIDGET_UPDATE, null, this, MyWidgetTorchProvider::class.java).apply {
|
||||
putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, intArrayOf(mWidgetId))
|
||||
putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, intArrayOf(viewModel.widgetId.value))
|
||||
sendBroadcast(this)
|
||||
}
|
||||
|
||||
updateBrightDisplayWidget()
|
||||
}
|
||||
|
||||
private fun updateColors() {
|
||||
mWidgetColor = mWidgetColorWithoutTransparency.adjustAlpha(mWidgetAlpha)
|
||||
config_widget_color.setFillWithStroke(mWidgetColor, mWidgetColor)
|
||||
config_image.background.mutate().applyColorFilter(mWidgetColor)
|
||||
}
|
||||
|
||||
private val seekbarChangeListener = object : SeekBar.OnSeekBarChangeListener {
|
||||
override fun onProgressChanged(seekBar: SeekBar, progress: Int, fromUser: Boolean) {
|
||||
mWidgetAlpha = progress.toFloat() / 100.toFloat()
|
||||
updateColors()
|
||||
}
|
||||
|
||||
override fun onStartTrackingTouch(seekBar: SeekBar) {}
|
||||
|
||||
override fun onStopTrackingTouch(seekBar: SeekBar) {}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,45 @@
|
|||
package com.simplemobiletools.flashlight.activities.viewmodel
|
||||
|
||||
import android.app.Application
|
||||
import android.graphics.Color
|
||||
import androidx.lifecycle.AndroidViewModel
|
||||
import com.simplemobiletools.flashlight.R
|
||||
import com.simplemobiletools.flashlight.extensions.config
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.asStateFlow
|
||||
|
||||
internal class WidgetConfigureViewModel(
|
||||
application: Application
|
||||
) : AndroidViewModel(application) {
|
||||
|
||||
|
||||
private val _widgetAlpha = MutableStateFlow(0f)
|
||||
val widgetAlpha = _widgetAlpha.asStateFlow()
|
||||
|
||||
private val _widgetId = MutableStateFlow(0)
|
||||
val widgetId = _widgetId.asStateFlow()
|
||||
|
||||
private val _widgetColor = MutableStateFlow(0)
|
||||
val widgetColor = _widgetColor.asStateFlow()
|
||||
|
||||
fun changeAlpha(newAlpha: Float) {
|
||||
_widgetAlpha.value = newAlpha
|
||||
}
|
||||
|
||||
fun updateColor(newColor: Int) {
|
||||
_widgetColor.value = newColor
|
||||
}
|
||||
|
||||
fun setWidgetId(widgetId: Int) {
|
||||
_widgetId.value = widgetId
|
||||
}
|
||||
|
||||
init {
|
||||
_widgetColor.value = application.config.widgetBgColor
|
||||
if (_widgetColor.value == application.resources.getColor(R.color.default_widget_bg_color, null) && application.config.isUsingSystemTheme) {
|
||||
_widgetColor.value = application.resources.getColor(com.simplemobiletools.commons.R.color.you_primary_color, application.theme)
|
||||
}
|
||||
|
||||
_widgetAlpha.value = Color.alpha(_widgetColor.value) / 255f
|
||||
}
|
||||
}
|
|
@ -0,0 +1,143 @@
|
|||
package com.simplemobiletools.flashlight.dialogs
|
||||
|
||||
import androidx.annotation.StringRes
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.foundation.text.KeyboardOptions
|
||||
import androidx.compose.material3.*
|
||||
import androidx.compose.runtime.*
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.text.input.KeyboardType
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.simplemobiletools.commons.R
|
||||
import com.simplemobiletools.commons.compose.alert_dialog.AlertDialogState
|
||||
import com.simplemobiletools.commons.compose.alert_dialog.DialogSurface
|
||||
import com.simplemobiletools.commons.compose.alert_dialog.dialogTextColor
|
||||
import com.simplemobiletools.commons.compose.alert_dialog.rememberAlertDialogState
|
||||
import com.simplemobiletools.commons.compose.extensions.MyDevices
|
||||
import com.simplemobiletools.commons.compose.theme.AppThemeSurface
|
||||
import com.simplemobiletools.commons.compose.theme.SimpleTheme
|
||||
import kotlinx.collections.immutable.toImmutableList
|
||||
|
||||
@Composable
|
||||
fun SleepTimerCustomAlertDialog(
|
||||
alertDialogState: AlertDialogState,
|
||||
modifier: Modifier = Modifier,
|
||||
onConfirmClick: (seconds: Int) -> Unit,
|
||||
onCancelClick: (() -> Unit)? = null
|
||||
) {
|
||||
var selectedItem by remember { mutableIntStateOf(0) }
|
||||
var value by remember { mutableStateOf("") }
|
||||
val items = remember {
|
||||
listOf(UnitItem(R.string.minutes_raw, 60), UnitItem(R.string.seconds_raw, 1)).toImmutableList()
|
||||
}
|
||||
|
||||
|
||||
AlertDialog(
|
||||
onDismissRequest = alertDialogState::hide
|
||||
) {
|
||||
DialogSurface(
|
||||
modifier = modifier
|
||||
) {
|
||||
Column(
|
||||
modifier = Modifier.padding(all = 24.dp)
|
||||
) {
|
||||
Text(
|
||||
modifier = Modifier.padding(bottom = SimpleTheme.dimens.padding.extraLarge),
|
||||
text = stringResource(id = R.string.sleep_timer),
|
||||
style = SimpleTheme.typography.headlineSmall,
|
||||
color = SimpleTheme.colorScheme.onSurface
|
||||
)
|
||||
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.padding(
|
||||
horizontal = SimpleTheme.dimens.padding.extraLarge
|
||||
)
|
||||
.padding(
|
||||
top = SimpleTheme.dimens.padding.extraLarge
|
||||
)
|
||||
) {
|
||||
OutlinedTextField(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(
|
||||
bottom = SimpleTheme.dimens.padding.large
|
||||
),
|
||||
value = value,
|
||||
onValueChange = {
|
||||
value = it.filter { it.isDigit() }
|
||||
},
|
||||
label = {
|
||||
Text(stringResource(id = R.string.value))
|
||||
},
|
||||
colors = OutlinedTextFieldDefaults.colors(
|
||||
disabledTextColor = dialogTextColor,
|
||||
disabledBorderColor = SimpleTheme.colorScheme.primary,
|
||||
disabledLabelColor = SimpleTheme.colorScheme.primary,
|
||||
),
|
||||
keyboardOptions = KeyboardOptions(
|
||||
keyboardType = KeyboardType.Number
|
||||
)
|
||||
)
|
||||
|
||||
items.forEachIndexed { index, item ->
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.clickable {
|
||||
selectedItem = index
|
||||
}
|
||||
.padding(vertical = SimpleTheme.dimens.padding.large)
|
||||
.fillMaxWidth(),
|
||||
verticalAlignment = Alignment.CenterVertically
|
||||
) {
|
||||
RadioButton(
|
||||
modifier = Modifier.padding(horizontal = SimpleTheme.dimens.padding.small),
|
||||
selected = index == selectedItem,
|
||||
onClick = null
|
||||
)
|
||||
Text(
|
||||
text = stringResource(id = item.stringResId)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Row(
|
||||
Modifier.fillMaxWidth(), verticalAlignment = Alignment.CenterVertically,
|
||||
horizontalArrangement = Arrangement.End
|
||||
) {
|
||||
TextButton(onClick = {
|
||||
onCancelClick?.invoke()
|
||||
alertDialogState.hide()
|
||||
}) {
|
||||
Text(text = stringResource(id = R.string.cancel))
|
||||
}
|
||||
TextButton(onClick = {
|
||||
val enteredValue = Integer.valueOf(value.ifEmpty { "0" })
|
||||
onConfirmClick(enteredValue * items[selectedItem].multiplier)
|
||||
alertDialogState.hide()
|
||||
}) {
|
||||
Text(text = stringResource(id = R.string.ok))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private data class UnitItem(@StringRes val stringResId: Int, val multiplier: Int)
|
||||
|
||||
@Composable
|
||||
@MyDevices
|
||||
private fun SleepTimerCustomAlertDialogPreview() {
|
||||
AppThemeSurface {
|
||||
SleepTimerCustomAlertDialog(
|
||||
alertDialogState = rememberAlertDialogState(),
|
||||
onConfirmClick = {},
|
||||
onCancelClick = {},
|
||||
)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,117 @@
|
|||
package com.simplemobiletools.flashlight.extensions
|
||||
|
||||
import android.app.Activity
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.net.Uri
|
||||
import android.os.Build
|
||||
import android.provider.Settings
|
||||
import androidx.annotation.RequiresApi
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import com.simplemobiletools.commons.activities.AboutActivity
|
||||
import com.simplemobiletools.commons.activities.CustomizationActivity
|
||||
import com.simplemobiletools.commons.compose.alert_dialog.rememberAlertDialogState
|
||||
import com.simplemobiletools.commons.compose.extensions.getActivity
|
||||
import com.simplemobiletools.commons.compose.extensions.onEventValue
|
||||
import com.simplemobiletools.commons.dialogs.FeatureLockedAlertDialog
|
||||
import com.simplemobiletools.commons.extensions.hideKeyboard
|
||||
import com.simplemobiletools.commons.extensions.isOrWasThankYouInstalled
|
||||
import com.simplemobiletools.commons.extensions.openDeviceSettings
|
||||
import com.simplemobiletools.commons.helpers.*
|
||||
import com.simplemobiletools.commons.models.FAQItem
|
||||
import com.simplemobiletools.flashlight.R
|
||||
|
||||
internal fun Activity.startAboutActivity(
|
||||
appNameId: Int, licenseMask: Long, versionName: String, faqItems: ArrayList<FAQItem>, showFAQBeforeMail: Boolean,
|
||||
getAppIconIDs: ArrayList<Int> = getAppIconIDs(),
|
||||
getAppLauncherName: String = launcherName()
|
||||
) {
|
||||
hideKeyboard()
|
||||
Intent(applicationContext, AboutActivity::class.java).apply {
|
||||
putExtra(APP_ICON_IDS, getAppIconIDs)
|
||||
putExtra(APP_LAUNCHER_NAME, getAppLauncherName)
|
||||
putExtra(APP_NAME, getString(appNameId))
|
||||
putExtra(APP_LICENSES, licenseMask)
|
||||
putExtra(APP_VERSION_NAME, versionName)
|
||||
putExtra(APP_FAQ, faqItems)
|
||||
putExtra(SHOW_FAQ_BEFORE_MAIL, showFAQBeforeMail)
|
||||
startActivity(this)
|
||||
}
|
||||
}
|
||||
|
||||
internal fun Activity.startCustomizationActivity(
|
||||
getAppIconIDs: ArrayList<Int> = getAppIconIDs(),
|
||||
getAppLauncherName: String = launcherName()
|
||||
) {
|
||||
Intent(applicationContext, CustomizationActivity::class.java).apply {
|
||||
putExtra(APP_ICON_IDS, getAppIconIDs)
|
||||
putExtra(APP_LAUNCHER_NAME, getAppLauncherName)
|
||||
startActivity(this)
|
||||
}
|
||||
}
|
||||
|
||||
@RequiresApi(Build.VERSION_CODES.TIRAMISU)
|
||||
internal fun Activity.launchChangeAppLanguageIntent() {
|
||||
try {
|
||||
Intent(Settings.ACTION_APP_LOCALE_SETTINGS).apply {
|
||||
data = Uri.fromParts("package", packageName, null)
|
||||
startActivity(this)
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
openDeviceSettings()
|
||||
}
|
||||
}
|
||||
|
||||
private fun getAppIconIDs() = arrayListOf(
|
||||
R.mipmap.ic_launcher_red,
|
||||
R.mipmap.ic_launcher_pink,
|
||||
R.mipmap.ic_launcher_purple,
|
||||
R.mipmap.ic_launcher_deep_purple,
|
||||
R.mipmap.ic_launcher_indigo,
|
||||
R.mipmap.ic_launcher_blue,
|
||||
R.mipmap.ic_launcher_light_blue,
|
||||
R.mipmap.ic_launcher_cyan,
|
||||
R.mipmap.ic_launcher_teal,
|
||||
R.mipmap.ic_launcher_green,
|
||||
R.mipmap.ic_launcher_light_green,
|
||||
R.mipmap.ic_launcher_lime,
|
||||
R.mipmap.ic_launcher_yellow,
|
||||
R.mipmap.ic_launcher_amber,
|
||||
R.mipmap.ic_launcher,
|
||||
R.mipmap.ic_launcher_deep_orange,
|
||||
R.mipmap.ic_launcher_brown,
|
||||
R.mipmap.ic_launcher_blue_grey,
|
||||
R.mipmap.ic_launcher_grey_black
|
||||
)
|
||||
|
||||
private fun Context.launcherName() = getString(R.string.app_launcher_name)
|
||||
|
||||
@Composable
|
||||
fun CheckFeatureLocked(
|
||||
skipCheck: Boolean
|
||||
) {
|
||||
val context = LocalContext.current.getActivity()
|
||||
val isOrWasThankYouInstalled = onEventValue {
|
||||
context.isOrWasThankYouInstalled()
|
||||
}
|
||||
val featureLockedAlertDialogState = rememberAlertDialogState().apply {
|
||||
DialogMember {
|
||||
FeatureLockedAlertDialog(
|
||||
alertDialogState = this,
|
||||
cancelCallback = {
|
||||
if (!isOrWasThankYouInstalled) {
|
||||
context.finish()
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
LaunchedEffect(isOrWasThankYouInstalled) {
|
||||
when {
|
||||
!skipCheck && !isOrWasThankYouInstalled -> featureLockedAlertDialogState.show()
|
||||
isOrWasThankYouInstalled -> featureLockedAlertDialogState.hide()
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
package com.simplemobiletools.flashlight.helpers
|
||||
|
||||
import androidx.compose.runtime.Immutable
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
|
||||
@Immutable
|
||||
object AppDimensions {
|
||||
val seekbarWidth = 250.dp
|
||||
val seekbarHeight = 20.dp
|
||||
val mainButtonSize = 180.dp
|
||||
val smallerButtonSize = 60.dp
|
||||
val sosTextSize = 26.sp
|
||||
val widgetColorPickerSize = 50.dp
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
package com.simplemobiletools.flashlight.helpers
|
||||
|
||||
import android.annotation.TargetApi
|
||||
import android.content.Intent
|
||||
import android.os.Build
|
||||
import android.service.quicksettings.TileService
|
||||
import com.simplemobiletools.flashlight.activities.BrightDisplayActivity
|
||||
|
||||
@TargetApi(Build.VERSION_CODES.N)
|
||||
class BrightDisplayTileService : TileService() {
|
||||
|
||||
override fun onClick() {
|
||||
val intent = Intent(applicationContext, BrightDisplayActivity::class.java)
|
||||
intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP or Intent.FLAG_ACTIVITY_NEW_TASK)
|
||||
startActivityAndCollapse(intent)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,97 @@
|
|||
package com.simplemobiletools.flashlight.helpers
|
||||
|
||||
import android.content.Context
|
||||
import android.hardware.camera2.CameraCharacteristics
|
||||
import android.hardware.camera2.CameraManager
|
||||
import android.os.Handler
|
||||
import com.simplemobiletools.commons.extensions.showErrorToast
|
||||
import com.simplemobiletools.commons.helpers.isTiramisuPlus
|
||||
import com.simplemobiletools.flashlight.extensions.config
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
internal class CameraFlash(
|
||||
private val context: Context,
|
||||
private var cameraTorchListener: CameraTorchListener? = null,
|
||||
) {
|
||||
private val manager = context.getSystemService(Context.CAMERA_SERVICE) as CameraManager
|
||||
private val cameraId: String
|
||||
|
||||
private val scope = CoroutineScope(Dispatchers.Default)
|
||||
|
||||
private val torchCallback = object : CameraManager.TorchCallback() {
|
||||
override fun onTorchModeChanged(cameraId: String, enabled: Boolean) {
|
||||
cameraTorchListener?.onTorchEnabled(enabled)
|
||||
}
|
||||
|
||||
override fun onTorchModeUnavailable(cameraId: String) {
|
||||
cameraTorchListener?.onTorchUnavailable()
|
||||
}
|
||||
}
|
||||
|
||||
init {
|
||||
cameraId = try {
|
||||
manager.cameraIdList[0] ?: "0"
|
||||
} catch (e: Exception) {
|
||||
context.showErrorToast(e)
|
||||
"0"
|
||||
}
|
||||
}
|
||||
|
||||
fun toggleFlashlight(enable: Boolean) {
|
||||
try {
|
||||
if (supportsBrightnessControl() && enable) {
|
||||
val brightnessLevel = getCurrentBrightnessLevel()
|
||||
changeTorchBrightness(brightnessLevel)
|
||||
} else {
|
||||
manager.setTorchMode(cameraId, enable)
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
scope.launch {
|
||||
MyCameraImpl.cameraError.emit(Unit)
|
||||
}
|
||||
throw e
|
||||
}
|
||||
}
|
||||
|
||||
fun changeTorchBrightness(level: Int) {
|
||||
if (isTiramisuPlus()) {
|
||||
manager.turnOnTorchWithStrengthLevel(cameraId, level)
|
||||
}
|
||||
}
|
||||
|
||||
fun getMaximumBrightnessLevel(): Int {
|
||||
return if (isTiramisuPlus()) {
|
||||
val characteristics = manager.getCameraCharacteristics(cameraId)
|
||||
characteristics.get(CameraCharacteristics.FLASH_INFO_STRENGTH_MAXIMUM_LEVEL) ?: MIN_BRIGHTNESS_LEVEL
|
||||
} else {
|
||||
MIN_BRIGHTNESS_LEVEL
|
||||
}
|
||||
}
|
||||
|
||||
fun supportsBrightnessControl(): Boolean {
|
||||
val maxBrightnessLevel = getMaximumBrightnessLevel()
|
||||
return maxBrightnessLevel > MIN_BRIGHTNESS_LEVEL
|
||||
}
|
||||
|
||||
fun getCurrentBrightnessLevel(): Int {
|
||||
var brightnessLevel = context.config.brightnessLevel
|
||||
if (brightnessLevel == DEFAULT_BRIGHTNESS_LEVEL) {
|
||||
brightnessLevel = getMaximumBrightnessLevel()
|
||||
}
|
||||
return brightnessLevel
|
||||
}
|
||||
|
||||
fun initialize() {
|
||||
manager.registerTorchCallback(torchCallback, Handler(context.mainLooper))
|
||||
}
|
||||
|
||||
fun unregisterListeners() {
|
||||
manager.unregisterTorchCallback(torchCallback)
|
||||
}
|
||||
|
||||
fun release() {
|
||||
cameraTorchListener = null
|
||||
}
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
package com.simplemobiletools.flashlight.helpers
|
||||
|
||||
interface CameraTorchListener {
|
||||
fun onTorchEnabled(isEnabled:Boolean)
|
||||
|
||||
fun onTorchUnavailable()
|
||||
}
|
|
@ -13,18 +13,26 @@ class Config(context: Context) : BaseConfig(context) {
|
|||
get() = prefs.getBoolean(BRIGHT_DISPLAY, true)
|
||||
set(brightDisplay) = prefs.edit().putBoolean(BRIGHT_DISPLAY, brightDisplay).apply()
|
||||
|
||||
val brightDisplayFlow = ::brightDisplay.asFlowNonNull(emitOnCollect = true)
|
||||
|
||||
var stroboscope: Boolean
|
||||
get() = prefs.getBoolean(STROBOSCOPE, true)
|
||||
set(stroboscope) = prefs.edit().putBoolean(STROBOSCOPE, stroboscope).apply()
|
||||
|
||||
val stroboscopeFlow = ::stroboscope.asFlowNonNull(emitOnCollect = true)
|
||||
|
||||
var sos: Boolean
|
||||
get() = prefs.getBoolean(SOS, true)
|
||||
set(sos) = prefs.edit().putBoolean(SOS, sos).apply()
|
||||
|
||||
val sosFlow = ::sos.asFlowNonNull(emitOnCollect = true)
|
||||
|
||||
var turnFlashlightOn: Boolean
|
||||
get() = prefs.getBoolean(TURN_FLASHLIGHT_ON, false)
|
||||
set(turnFlashlightOn) = prefs.edit().putBoolean(TURN_FLASHLIGHT_ON, turnFlashlightOn).apply()
|
||||
|
||||
val turnFlashlightOnFlow = ::turnFlashlightOn.asFlowNonNull()
|
||||
|
||||
var stroboscopeProgress: Int
|
||||
get() = prefs.getInt(STROBOSCOPE_PROGRESS, 1000)
|
||||
set(stroboscopeProgress) = prefs.edit().putInt(STROBOSCOPE_PROGRESS, stroboscopeProgress).apply()
|
||||
|
@ -37,7 +45,25 @@ class Config(context: Context) : BaseConfig(context) {
|
|||
get() = prefs.getInt(BRIGHT_DISPLAY_COLOR, Color.WHITE)
|
||||
set(brightDisplayColor) = prefs.edit().putInt(BRIGHT_DISPLAY_COLOR, brightDisplayColor).apply()
|
||||
|
||||
val brightDisplayColorFlow = ::brightDisplayColor.asFlowNonNull()
|
||||
|
||||
var forcePortraitMode: Boolean
|
||||
get() = prefs.getBoolean(FORCE_PORTRAIT_MODE, true)
|
||||
set(forcePortraitMode) = prefs.edit().putBoolean(FORCE_PORTRAIT_MODE, forcePortraitMode).apply()
|
||||
|
||||
val forcePortraitModeFlow = ::forcePortraitMode.asFlowNonNull()
|
||||
|
||||
var brightnessLevel: Int
|
||||
get() = prefs.getInt(BRIGHTNESS_LEVEL, DEFAULT_BRIGHTNESS_LEVEL)
|
||||
set(brightnessLevel) = prefs.edit().putInt(BRIGHTNESS_LEVEL, brightnessLevel).apply()
|
||||
|
||||
var lastSleepTimerSeconds: Int
|
||||
get() = prefs.getInt(LAST_SLEEP_TIMER_SECONDS, 30 * 60)
|
||||
set(lastSleepTimerSeconds) = prefs.edit().putInt(LAST_SLEEP_TIMER_SECONDS, lastSleepTimerSeconds).apply()
|
||||
|
||||
val lastSleepTimerSecondsFlow = ::lastSleepTimerSeconds.asFlowNonNull()
|
||||
|
||||
var sleepInTS: Long
|
||||
get() = prefs.getLong(SLEEP_IN_TS, 0)
|
||||
set(sleepInTS) = prefs.edit().putLong(SLEEP_IN_TS, sleepInTS).apply()
|
||||
}
|
||||
|
|
|
@ -11,3 +11,8 @@ const val STROBOSCOPE_FREQUENCY = "stroboscope_frequency"
|
|||
const val STROBOSCOPE_PROGRESS = "stroboscope_progress"
|
||||
const val FORCE_PORTRAIT_MODE = "force_portrait_mode"
|
||||
const val SOS = "sos"
|
||||
const val BRIGHTNESS_LEVEL = "brightness_level"
|
||||
const val LAST_SLEEP_TIMER_SECONDS = "last_sleep_timer_seconds"
|
||||
const val SLEEP_IN_TS = "sleep_in_ts"
|
||||
const val MIN_BRIGHTNESS_LEVEL = 1
|
||||
const val DEFAULT_BRIGHTNESS_LEVEL = -1
|
||||
|
|
|
@ -6,7 +6,7 @@ import android.service.quicksettings.Tile
|
|||
import android.service.quicksettings.TileService
|
||||
|
||||
@TargetApi(Build.VERSION_CODES.N)
|
||||
class MyTileService : TileService() {
|
||||
class FlashlightTileService : TileService() {
|
||||
|
||||
override fun onClick() {
|
||||
MyCameraImpl.newInstance(this).toggleFlashlight()
|
|
@ -1,37 +0,0 @@
|
|||
package com.simplemobiletools.flashlight.helpers
|
||||
|
||||
import android.annotation.TargetApi
|
||||
import android.content.Context
|
||||
import android.hardware.camera2.CameraManager
|
||||
import android.os.Build
|
||||
import android.os.Handler
|
||||
import com.simplemobiletools.commons.extensions.showErrorToast
|
||||
import com.simplemobiletools.flashlight.models.Events
|
||||
import org.greenrobot.eventbus.EventBus
|
||||
|
||||
internal class MarshmallowCamera constructor(val context: Context) {
|
||||
|
||||
private val manager = context.getSystemService(Context.CAMERA_SERVICE) as CameraManager
|
||||
private var cameraId: String? = null
|
||||
|
||||
init {
|
||||
try {
|
||||
cameraId = manager.cameraIdList[0] ?: "0"
|
||||
} catch (e: Exception) {
|
||||
context.showErrorToast(e)
|
||||
}
|
||||
}
|
||||
|
||||
@TargetApi(Build.VERSION_CODES.M)
|
||||
fun toggleMarshmallowFlashlight(enable: Boolean) {
|
||||
try {
|
||||
manager.setTorchMode(cameraId!!, enable)
|
||||
} catch (e: Exception) {
|
||||
context.showErrorToast(e)
|
||||
val mainRunnable = Runnable {
|
||||
EventBus.getDefault().post(Events.CameraUnavailable())
|
||||
}
|
||||
Handler(context.mainLooper).post(mainRunnable)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,35 +1,35 @@
|
|||
package com.simplemobiletools.flashlight.helpers
|
||||
|
||||
import android.content.Context
|
||||
import android.graphics.SurfaceTexture
|
||||
import android.hardware.Camera
|
||||
import android.os.Handler
|
||||
import com.simplemobiletools.commons.extensions.showErrorToast
|
||||
import com.simplemobiletools.commons.extensions.toast
|
||||
import com.simplemobiletools.commons.helpers.isMarshmallowPlus
|
||||
import com.simplemobiletools.commons.helpers.isNougatPlus
|
||||
import com.simplemobiletools.flashlight.R
|
||||
import com.simplemobiletools.flashlight.extensions.config
|
||||
import com.simplemobiletools.flashlight.extensions.updateWidgets
|
||||
import com.simplemobiletools.flashlight.models.Events
|
||||
import org.greenrobot.eventbus.EventBus
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.flow.MutableSharedFlow
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.asSharedFlow
|
||||
import kotlinx.coroutines.flow.asStateFlow
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
class MyCameraImpl(val context: Context) {
|
||||
class MyCameraImpl private constructor(private val context: Context, private var cameraTorchListener: CameraTorchListener? = null) {
|
||||
var stroboFrequency = 1000L
|
||||
|
||||
companion object {
|
||||
var isFlashlightOn = false
|
||||
private val SOS = arrayListOf(250L, 250L, 250L, 250L, 250L, 250L, 500L, 250L, 500L, 250L, 500L, 250L, 250L, 250L, 250L, 250L, 250L, 1000L)
|
||||
|
||||
private var camera: Camera? = null
|
||||
private var params: Camera.Parameters? = null
|
||||
private var isMarshmallow = false
|
||||
private var u = 200L // The length of one dit (Time unit)
|
||||
private val SOS = listOf(u, u, u, u, u, u * 3, u * 3, u, u * 3, u, u * 3, u * 3, u, u, u, u, u, u * 7)
|
||||
|
||||
private var shouldEnableFlashlight = false
|
||||
private var shouldEnableStroboscope = false
|
||||
private var shouldEnableSOS = false
|
||||
private var isStroboSOS = false // are we sending SOS, or casual stroboscope?
|
||||
|
||||
private var marshmallowCamera: MarshmallowCamera? = null
|
||||
private var cameraFlash: CameraFlash? = null
|
||||
|
||||
@Volatile
|
||||
private var shouldStroboscopeStop = false
|
||||
|
@ -40,21 +40,43 @@ class MyCameraImpl(val context: Context) {
|
|||
@Volatile
|
||||
private var isSOSRunning = false
|
||||
|
||||
fun newInstance(context: Context) = MyCameraImpl(context)
|
||||
val cameraError = MutableSharedFlow<Unit>()
|
||||
|
||||
fun newInstance(context: Context, cameraTorchListener: CameraTorchListener? = null) = MyCameraImpl(context, cameraTorchListener)
|
||||
}
|
||||
|
||||
private val scope = CoroutineScope(Dispatchers.Default)
|
||||
|
||||
private val _flashlightOn = MutableStateFlow(false)
|
||||
val flashlightOnFlow = _flashlightOn.asStateFlow()
|
||||
|
||||
private val cameraFlash: CameraFlash?
|
||||
get() {
|
||||
if (MyCameraImpl.cameraFlash == null) {
|
||||
handleCameraSetup()
|
||||
}
|
||||
return MyCameraImpl.cameraFlash
|
||||
}
|
||||
|
||||
init {
|
||||
isMarshmallow = isMarshmallowPlus()
|
||||
handleCameraSetup()
|
||||
stroboFrequency = context.config.stroboscopeFrequency
|
||||
}
|
||||
|
||||
private val _sosDisabled = MutableSharedFlow<Unit>()
|
||||
val sosDisabled = _sosDisabled.asSharedFlow()
|
||||
|
||||
private val _stroboscopeDisabled = MutableSharedFlow<Unit>()
|
||||
val stroboscopeDisabled = _stroboscopeDisabled.asSharedFlow()
|
||||
|
||||
fun toggleFlashlight() {
|
||||
isFlashlightOn = !isFlashlightOn
|
||||
checkFlashlight()
|
||||
}
|
||||
|
||||
fun toggleStroboscope(): Boolean {
|
||||
handleCameraSetup()
|
||||
|
||||
if (isSOSRunning) {
|
||||
stopSOS()
|
||||
shouldEnableStroboscope = true
|
||||
|
@ -66,6 +88,10 @@ class MyCameraImpl(val context: Context) {
|
|||
disableFlashlight()
|
||||
}
|
||||
|
||||
cameraFlash.runOrToast {
|
||||
unregisterListeners()
|
||||
}
|
||||
|
||||
if (!tryInitCamera()) {
|
||||
return false
|
||||
}
|
||||
|
@ -81,10 +107,14 @@ class MyCameraImpl(val context: Context) {
|
|||
|
||||
fun stopStroboscope() {
|
||||
shouldStroboscopeStop = true
|
||||
EventBus.getDefault().post(Events.StopStroboscope())
|
||||
scope.launch {
|
||||
_stroboscopeDisabled.emit(Unit)
|
||||
}
|
||||
}
|
||||
|
||||
fun toggleSOS(): Boolean {
|
||||
handleCameraSetup()
|
||||
|
||||
if (isStroboscopeRunning) {
|
||||
stopStroboscope()
|
||||
shouldEnableSOS = true
|
||||
|
@ -104,6 +134,10 @@ class MyCameraImpl(val context: Context) {
|
|||
disableFlashlight()
|
||||
}
|
||||
|
||||
cameraFlash.runOrToast {
|
||||
unregisterListeners()
|
||||
}
|
||||
|
||||
return if (isSOSRunning) {
|
||||
stopSOS()
|
||||
false
|
||||
|
@ -115,62 +149,34 @@ class MyCameraImpl(val context: Context) {
|
|||
|
||||
fun stopSOS() {
|
||||
shouldStroboscopeStop = true
|
||||
EventBus.getDefault().post(Events.StopSOS())
|
||||
scope.launch {
|
||||
_sosDisabled.emit(Unit)
|
||||
}
|
||||
}
|
||||
|
||||
private fun tryInitCamera(): Boolean {
|
||||
if (!isNougatPlus()) {
|
||||
if (camera == null) {
|
||||
initCamera()
|
||||
}
|
||||
|
||||
if (camera == null) {
|
||||
context.toast(R.string.camera_error)
|
||||
return false
|
||||
}
|
||||
handleCameraSetup()
|
||||
if (cameraFlash == null) {
|
||||
context.toast(R.string.camera_error)
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
fun handleCameraSetup() {
|
||||
if (isMarshmallow) {
|
||||
setupMarshmallowCamera()
|
||||
} else {
|
||||
setupCamera()
|
||||
}
|
||||
}
|
||||
|
||||
private fun setupMarshmallowCamera() {
|
||||
if (marshmallowCamera == null) {
|
||||
marshmallowCamera = MarshmallowCamera(context)
|
||||
}
|
||||
}
|
||||
|
||||
private fun setupCamera() {
|
||||
if (isMarshmallow) {
|
||||
return
|
||||
}
|
||||
|
||||
if (camera == null) {
|
||||
initCamera()
|
||||
}
|
||||
}
|
||||
|
||||
private fun initCamera() {
|
||||
try {
|
||||
camera = Camera.open()
|
||||
params = camera!!.parameters
|
||||
params!!.flashMode = Camera.Parameters.FLASH_MODE_OFF
|
||||
camera!!.parameters = params
|
||||
if (MyCameraImpl.cameraFlash == null) {
|
||||
MyCameraImpl.cameraFlash = CameraFlash(context, cameraTorchListener)
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
EventBus.getDefault().post(Events.CameraUnavailable())
|
||||
scope.launch {
|
||||
cameraError.emit(Unit)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun checkFlashlight() {
|
||||
if (camera == null) {
|
||||
handleCameraSetup()
|
||||
}
|
||||
handleCameraSetup()
|
||||
|
||||
if (isFlashlightOn) {
|
||||
enableFlashlight()
|
||||
|
@ -186,25 +192,15 @@ class MyCameraImpl(val context: Context) {
|
|||
return
|
||||
}
|
||||
|
||||
if (isMarshmallow) {
|
||||
toggleMarshmallowFlashlight(true)
|
||||
} else {
|
||||
try {
|
||||
if (camera == null || params == null || camera!!.parameters == null) {
|
||||
return
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
return
|
||||
}
|
||||
|
||||
params!!.flashMode = Camera.Parameters.FLASH_MODE_TORCH
|
||||
camera!!.parameters = params
|
||||
try {
|
||||
camera!!.startPreview()
|
||||
} catch (e: Exception) {
|
||||
context.showErrorToast(e)
|
||||
disableFlashlight()
|
||||
try {
|
||||
cameraFlash!!.run {
|
||||
initialize()
|
||||
toggleFlashlight(true)
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
context.showErrorToast(e)
|
||||
disableFlashlight()
|
||||
return
|
||||
}
|
||||
|
||||
val mainRunnable = Runnable { stateChanged(true) }
|
||||
|
@ -216,41 +212,45 @@ class MyCameraImpl(val context: Context) {
|
|||
return
|
||||
}
|
||||
|
||||
if (isMarshmallow) {
|
||||
toggleMarshmallowFlashlight(false)
|
||||
} else {
|
||||
try {
|
||||
if (camera == null || params == null || camera!!.parameters == null) {
|
||||
return
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
return
|
||||
}
|
||||
|
||||
params!!.flashMode = Camera.Parameters.FLASH_MODE_OFF
|
||||
camera!!.parameters = params
|
||||
try {
|
||||
cameraFlash!!.toggleFlashlight(false)
|
||||
} catch (e: Exception) {
|
||||
context.showErrorToast(e)
|
||||
}
|
||||
stateChanged(false)
|
||||
releaseCamera()
|
||||
}
|
||||
|
||||
fun onTorchEnabled(isEnabled: Boolean) {
|
||||
if (isStroboscopeRunning || isSOSRunning) {
|
||||
return
|
||||
}
|
||||
if (isFlashlightOn != isEnabled) {
|
||||
stateChanged(isEnabled)
|
||||
}
|
||||
}
|
||||
|
||||
private fun stateChanged(isEnabled: Boolean) {
|
||||
isFlashlightOn = isEnabled
|
||||
EventBus.getDefault().post(Events.StateChanged(isEnabled))
|
||||
scope.launch {
|
||||
_flashlightOn.emit(isEnabled)
|
||||
}
|
||||
context.updateWidgets(isEnabled)
|
||||
}
|
||||
|
||||
private fun toggleMarshmallowFlashlight(enable: Boolean) {
|
||||
marshmallowCamera!!.toggleMarshmallowFlashlight(enable)
|
||||
}
|
||||
|
||||
fun releaseCamera() {
|
||||
cameraFlash.runOrToast {
|
||||
unregisterListeners()
|
||||
}
|
||||
|
||||
if (isFlashlightOn) {
|
||||
disableFlashlight()
|
||||
}
|
||||
|
||||
camera?.release()
|
||||
camera = null
|
||||
cameraFlash.runOrToast {
|
||||
release()
|
||||
}
|
||||
MyCameraImpl.cameraFlash = null
|
||||
cameraTorchListener = null
|
||||
|
||||
isFlashlightOn = false
|
||||
shouldStroboscopeStop = true
|
||||
|
@ -269,61 +269,45 @@ class MyCameraImpl(val context: Context) {
|
|||
}
|
||||
|
||||
var sosIndex = 0
|
||||
if (isNougatPlus()) {
|
||||
while (!shouldStroboscopeStop) {
|
||||
try {
|
||||
marshmallowCamera!!.toggleMarshmallowFlashlight(true)
|
||||
val onDuration = if (isStroboSOS) SOS[sosIndex++ % SOS.size] else stroboFrequency
|
||||
Thread.sleep(onDuration)
|
||||
marshmallowCamera!!.toggleMarshmallowFlashlight(false)
|
||||
val offDuration = if (isStroboSOS) SOS[sosIndex++ % SOS.size] else stroboFrequency
|
||||
Thread.sleep(offDuration)
|
||||
} catch (e: Exception) {
|
||||
shouldStroboscopeStop = true
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (camera == null) {
|
||||
initCamera()
|
||||
}
|
||||
|
||||
handleCameraSetup()
|
||||
while (!shouldStroboscopeStop) {
|
||||
try {
|
||||
val torchOn = camera!!.parameters ?: return@Runnable
|
||||
val torchOff = camera!!.parameters
|
||||
torchOn.flashMode = Camera.Parameters.FLASH_MODE_TORCH
|
||||
torchOff.flashMode = Camera.Parameters.FLASH_MODE_OFF
|
||||
|
||||
val dummy = SurfaceTexture(1)
|
||||
camera!!.setPreviewTexture(dummy)
|
||||
|
||||
camera!!.startPreview()
|
||||
|
||||
while (!shouldStroboscopeStop) {
|
||||
camera!!.parameters = torchOn
|
||||
val onDuration = if (isStroboSOS) SOS[sosIndex++ % SOS.size] else stroboFrequency
|
||||
Thread.sleep(onDuration)
|
||||
camera!!.parameters = torchOff
|
||||
val offDuration = if (isStroboSOS) SOS[sosIndex++ % SOS.size] else stroboFrequency
|
||||
Thread.sleep(offDuration)
|
||||
cameraFlash!!.run {
|
||||
toggleFlashlight(true)
|
||||
}
|
||||
|
||||
if (camera != null) {
|
||||
camera!!.parameters = torchOff
|
||||
if (!shouldEnableFlashlight || isMarshmallow) {
|
||||
camera!!.release()
|
||||
camera = null
|
||||
}
|
||||
val onDuration = if (isStroboSOS) SOS[sosIndex++ % SOS.size] else stroboFrequency
|
||||
Thread.sleep(onDuration)
|
||||
cameraFlash!!.run {
|
||||
toggleFlashlight(false)
|
||||
}
|
||||
} catch (e: RuntimeException) {
|
||||
val offDuration = if (isStroboSOS) SOS[sosIndex++ % SOS.size] else stroboFrequency
|
||||
Thread.sleep(offDuration)
|
||||
} catch (e: Exception) {
|
||||
shouldStroboscopeStop = true
|
||||
}
|
||||
}
|
||||
|
||||
// disable flash immediately if stroboscope is stopped and normal flash mode is disabled
|
||||
if (shouldStroboscopeStop && !shouldEnableFlashlight) {
|
||||
handleCameraSetup()
|
||||
cameraFlash.runOrToast {
|
||||
toggleFlashlight(false)
|
||||
release()
|
||||
}
|
||||
MyCameraImpl.cameraFlash = null
|
||||
}
|
||||
|
||||
shouldStroboscopeStop = false
|
||||
if (isStroboSOS) {
|
||||
isSOSRunning = false
|
||||
scope.launch {
|
||||
_sosDisabled.emit(Unit)
|
||||
}
|
||||
} else {
|
||||
isStroboscopeRunning = false
|
||||
scope.launch {
|
||||
_stroboscopeDisabled.emit(Unit)
|
||||
}
|
||||
}
|
||||
|
||||
when {
|
||||
|
@ -341,4 +325,43 @@ class MyCameraImpl(val context: Context) {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun getMaximumBrightnessLevel(): Int {
|
||||
return cameraFlash.runOrToastWithDefault(MIN_BRIGHTNESS_LEVEL) {
|
||||
getMaximumBrightnessLevel()
|
||||
}
|
||||
}
|
||||
|
||||
fun getCurrentBrightnessLevel(): Int {
|
||||
return cameraFlash.runOrToastWithDefault(DEFAULT_BRIGHTNESS_LEVEL) {
|
||||
getCurrentBrightnessLevel()
|
||||
}
|
||||
}
|
||||
|
||||
fun supportsBrightnessControl(): Boolean {
|
||||
return cameraFlash.runOrToastWithDefault(false) {
|
||||
supportsBrightnessControl()
|
||||
}
|
||||
}
|
||||
|
||||
fun updateBrightnessLevel(level: Int) {
|
||||
cameraFlash.runOrToast {
|
||||
changeTorchBrightness(level)
|
||||
}
|
||||
}
|
||||
|
||||
fun onCameraNotAvailable() {
|
||||
disableFlashlight()
|
||||
}
|
||||
|
||||
private fun <T> CameraFlash?.runOrToastWithDefault(defaultValue: T, block: CameraFlash.() -> T): T {
|
||||
return try {
|
||||
this!!.block()
|
||||
} catch (e: Exception) {
|
||||
context.showErrorToast(e)
|
||||
defaultValue
|
||||
}
|
||||
}
|
||||
|
||||
private fun CameraFlash?.runOrToast(block: CameraFlash.() -> Unit) = runOrToastWithDefault(Unit, block)
|
||||
}
|
||||
|
|
|
@ -44,7 +44,7 @@ class MyWidgetBrightDisplayProvider : AppWidgetProvider() {
|
|||
}
|
||||
|
||||
private fun getColoredIcon(context: Context, color: Int, alpha: Int): Bitmap {
|
||||
val drawable = context.resources.getColoredDrawableWithColor(R.drawable.ic_bright_display, color, alpha)
|
||||
val drawable = context.resources.getColoredDrawableWithColor(R.drawable.ic_bright_display_vector, color, alpha)
|
||||
return context.drawableToBitmap(drawable)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -69,7 +69,7 @@ class MyWidgetTorchProvider : AppWidgetProvider() {
|
|||
}
|
||||
|
||||
private fun getColoredIcon(context: Context, color: Int, alpha: Int): Bitmap {
|
||||
val drawable = context.resources.getColoredDrawableWithColor(R.drawable.ic_flashlight, color, alpha)
|
||||
val drawable = context.resources.getColoredDrawableWithColor(R.drawable.ic_flashlight_vector, color, alpha)
|
||||
return context.drawableToBitmap(drawable)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,12 @@
|
|||
package com.simplemobiletools.flashlight.helpers
|
||||
|
||||
import android.content.BroadcastReceiver
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import kotlin.system.exitProcess
|
||||
|
||||
class ShutDownReceiver : BroadcastReceiver() {
|
||||
override fun onReceive(context: Context?, intent: Intent?) {
|
||||
exitProcess(0)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,80 @@
|
|||
package com.simplemobiletools.flashlight.helpers
|
||||
|
||||
import android.app.AlarmManager
|
||||
import android.app.PendingIntent
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.os.CountDownTimer
|
||||
import com.simplemobiletools.commons.helpers.isSPlus
|
||||
import com.simplemobiletools.flashlight.extensions.config
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.flow.MutableSharedFlow
|
||||
import kotlinx.coroutines.flow.asSharedFlow
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlin.system.exitProcess
|
||||
|
||||
object SleepTimer {
|
||||
private var sleepTimer: CountDownTimer? = null
|
||||
private val _timeLeft = MutableSharedFlow<Int>()
|
||||
val timeLeft = _timeLeft.asSharedFlow()
|
||||
private val scope = CoroutineScope(Dispatchers.Default)
|
||||
|
||||
fun cancel() = synchronized(this@SleepTimer) {
|
||||
sleepTimer?.cancel()
|
||||
sleepTimer = null
|
||||
}
|
||||
|
||||
context(Context)
|
||||
fun startTimer() = synchronized(this@SleepTimer) {
|
||||
val millisInFuture = config.sleepInTS - System.currentTimeMillis() + 1000L
|
||||
sleepTimer?.cancel()
|
||||
sleepTimer = object : CountDownTimer(millisInFuture, 1000) {
|
||||
override fun onTick(millisUntilFinished: Long) {
|
||||
val seconds = (millisUntilFinished / 1000).toInt()
|
||||
scope.launch {
|
||||
_timeLeft.emit(seconds)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onFinish() {
|
||||
config.sleepInTS = 0
|
||||
scope.launch {
|
||||
_timeLeft.emit(0)
|
||||
}
|
||||
stopSleepTimerCountDown()
|
||||
exitProcess(0)
|
||||
}
|
||||
}
|
||||
|
||||
sleepTimer?.start()
|
||||
}
|
||||
}
|
||||
|
||||
internal fun Context.startSleepTimerCountDown() {
|
||||
(getSystemService(Context.ALARM_SERVICE) as AlarmManager).apply {
|
||||
if (!isSPlus() || canScheduleExactAlarms()) {
|
||||
setExactAndAllowWhileIdle(
|
||||
AlarmManager.RTC_WAKEUP,
|
||||
config.sleepInTS,
|
||||
getShutDownPendingIntent()
|
||||
)
|
||||
} else {
|
||||
setAndAllowWhileIdle(
|
||||
AlarmManager.RTC_WAKEUP,
|
||||
config.sleepInTS,
|
||||
getShutDownPendingIntent()
|
||||
)
|
||||
}
|
||||
}
|
||||
SleepTimer.startTimer()
|
||||
}
|
||||
|
||||
internal fun Context.stopSleepTimerCountDown() {
|
||||
(getSystemService(Context.ALARM_SERVICE) as AlarmManager).cancel(getShutDownPendingIntent())
|
||||
SleepTimer.cancel()
|
||||
config.sleepInTS = 0
|
||||
}
|
||||
|
||||
internal fun Context.getShutDownPendingIntent() =
|
||||
PendingIntent.getBroadcast(this, 0, Intent(this, ShutDownReceiver::class.java), PendingIntent.FLAG_IMMUTABLE)
|
|
@ -1,11 +0,0 @@
|
|||
package com.simplemobiletools.flashlight.models
|
||||
|
||||
class Events {
|
||||
class StateChanged(val isEnabled: Boolean)
|
||||
|
||||
class CameraUnavailable
|
||||
|
||||
class StopStroboscope
|
||||
|
||||
class StopSOS
|
||||
}
|
|
@ -0,0 +1,74 @@
|
|||
package com.simplemobiletools.flashlight.screens
|
||||
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.border
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.TextButton
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.toArgb
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.simplemobiletools.commons.compose.extensions.MyDevices
|
||||
import com.simplemobiletools.commons.compose.theme.AppThemeSurface
|
||||
import com.simplemobiletools.commons.compose.theme.SimpleTheme
|
||||
import com.simplemobiletools.commons.extensions.getContrastColor
|
||||
import com.simplemobiletools.flashlight.R
|
||||
import com.simplemobiletools.flashlight.views.AnimatedSleepTimer
|
||||
|
||||
@Composable
|
||||
internal fun BrightDisplayScreen(
|
||||
backgroundColor: Int,
|
||||
contrastColor: Int,
|
||||
onChangeColorPress: () -> Unit,
|
||||
sleepTimer: @Composable () -> Unit
|
||||
) {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.fillMaxSize()
|
||||
.background(Color(backgroundColor))
|
||||
.safeDrawingPadding()
|
||||
) {
|
||||
TextButton(
|
||||
modifier = Modifier
|
||||
.wrapContentSize()
|
||||
.align(Alignment.Center)
|
||||
.border(
|
||||
width = 1.dp,
|
||||
color = Color(contrastColor),
|
||||
shape = SimpleTheme.shapes.extraLarge
|
||||
),
|
||||
onClick = onChangeColorPress
|
||||
) {
|
||||
Text(
|
||||
text = stringResource(id = com.simplemobiletools.commons.R.string.change_color),
|
||||
color = Color(contrastColor)
|
||||
)
|
||||
}
|
||||
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.align(Alignment.BottomEnd)
|
||||
) {
|
||||
sleepTimer()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
@MyDevices
|
||||
private fun BrightDisplayScreenPreview() {
|
||||
AppThemeSurface {
|
||||
BrightDisplayScreen(
|
||||
backgroundColor = SimpleTheme.colorScheme.background.toArgb(),
|
||||
contrastColor = SimpleTheme.colorScheme.background.toArgb().getContrastColor(),
|
||||
sleepTimer = {
|
||||
AnimatedSleepTimer(timerText = "00:00", timerVisible = true, onTimerClosePress = {})
|
||||
},
|
||||
onChangeColorPress = {},
|
||||
)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,295 @@
|
|||
package com.simplemobiletools.flashlight.screens
|
||||
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.interaction.MutableInteractionSource
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.foundation.rememberScrollState
|
||||
import androidx.compose.foundation.verticalScroll
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.filled.Settings
|
||||
import androidx.compose.material.icons.outlined.Info
|
||||
import androidx.compose.material3.*
|
||||
import androidx.compose.runtime.*
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.painter.Painter
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.simplemobiletools.commons.compose.extensions.AdjustNavigationBarColors
|
||||
import com.simplemobiletools.commons.compose.extensions.MyDevices
|
||||
import com.simplemobiletools.commons.compose.extensions.rememberMutableInteractionSource
|
||||
import com.simplemobiletools.commons.compose.lists.*
|
||||
import com.simplemobiletools.commons.compose.menus.ActionItem
|
||||
import com.simplemobiletools.commons.compose.menus.ActionMenu
|
||||
import com.simplemobiletools.commons.compose.menus.OverflowMode
|
||||
import com.simplemobiletools.commons.compose.theme.AppThemeSurface
|
||||
import com.simplemobiletools.commons.compose.theme.SimpleTheme
|
||||
import com.simplemobiletools.flashlight.R
|
||||
import com.simplemobiletools.flashlight.helpers.AppDimensions
|
||||
import com.simplemobiletools.flashlight.views.AnimatedSleepTimer
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
import kotlinx.collections.immutable.toImmutableList
|
||||
|
||||
@Composable
|
||||
internal fun MainScreen(
|
||||
flashlightButton: @Composable () -> Unit,
|
||||
brightDisplayButton: @Composable () -> Unit,
|
||||
sosButton: @Composable () -> Unit,
|
||||
stroboscopeButton: @Composable () -> Unit,
|
||||
slidersSection: @Composable () -> Unit,
|
||||
sleepTimer: @Composable () -> Unit,
|
||||
showMoreApps: Boolean,
|
||||
openSettings: () -> Unit,
|
||||
openAbout: () -> Unit,
|
||||
openSleepTimer: () -> Unit,
|
||||
moreAppsFromUs: () -> Unit,
|
||||
) {
|
||||
AdjustNavigationBarColors()
|
||||
SimpleScaffold(
|
||||
customTopBar = { scrolledColor: Color, _: MutableInteractionSource, scrollBehavior: TopAppBarScrollBehavior, statusBarColor: Int, colorTransitionFraction: Float, contrastColor: Color ->
|
||||
TopAppBar(
|
||||
title = {},
|
||||
actions = {
|
||||
val actionMenus = remember { buildActionMenu(showMoreApps, openSettings, openAbout, openSleepTimer, moreAppsFromUs) }
|
||||
var isMenuVisible by remember { mutableStateOf(false) }
|
||||
ActionMenu(
|
||||
items = actionMenus,
|
||||
numIcons = 2,
|
||||
isMenuVisible = isMenuVisible,
|
||||
onMenuToggle = { isMenuVisible = it },
|
||||
iconsColor = scrolledColor
|
||||
)
|
||||
},
|
||||
scrollBehavior = scrollBehavior,
|
||||
colors = simpleTopAppBarColors(statusBarColor, colorTransitionFraction, contrastColor),
|
||||
modifier = Modifier.topAppBarPaddings(),
|
||||
windowInsets = topAppBarInsets()
|
||||
)
|
||||
}) {
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.fillMaxSize()
|
||||
.verticalScroll(rememberScrollState()),
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
verticalArrangement = Arrangement.SpaceEvenly
|
||||
) {
|
||||
flashlightButton()
|
||||
brightDisplayButton()
|
||||
sosButton()
|
||||
stroboscopeButton()
|
||||
slidersSection()
|
||||
Spacer(
|
||||
modifier = Modifier.size(SimpleTheme.dimens.padding.extraLarge)
|
||||
)
|
||||
}
|
||||
|
||||
Box(
|
||||
modifier = Modifier.align(Alignment.BottomEnd)
|
||||
.navigationBarsPadding(),
|
||||
) {
|
||||
sleepTimer()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
internal fun FlashlightButton(
|
||||
flashlightActive: Boolean,
|
||||
onFlashlightPress: () -> Unit,
|
||||
) {
|
||||
Icon(
|
||||
modifier = Modifier
|
||||
.size(AppDimensions.mainButtonSize)
|
||||
.padding(vertical = SimpleTheme.dimens.padding.large)
|
||||
.clickable(
|
||||
indication = null,
|
||||
interactionSource = rememberMutableInteractionSource(),
|
||||
onClick = onFlashlightPress
|
||||
),
|
||||
painter = painterResource(id = R.drawable.ic_flashlight_vector),
|
||||
contentDescription = stringResource(id = com.simplemobiletools.commons.R.string.flashlight_short),
|
||||
tint = if (flashlightActive) SimpleTheme.colorScheme.primary else SimpleTheme.colorScheme.onSurface
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
internal fun BrightDisplayButton(
|
||||
onBrightDisplayPress: () -> Unit,
|
||||
) {
|
||||
SmallButton(
|
||||
painter = painterResource(id = R.drawable.ic_bright_display_vector),
|
||||
contentDescription = stringResource(id = R.string.bright_display),
|
||||
isActive = false,
|
||||
onPress = onBrightDisplayPress
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
internal fun SosButton(
|
||||
sosActive: Boolean,
|
||||
onSosButtonPress: () -> Unit,
|
||||
) {
|
||||
Text(
|
||||
modifier = Modifier
|
||||
.padding(vertical = SimpleTheme.dimens.padding.large)
|
||||
.clickable(
|
||||
indication = null,
|
||||
interactionSource = rememberMutableInteractionSource(),
|
||||
onClick = onSosButtonPress
|
||||
),
|
||||
text = stringResource(id = R.string.sos),
|
||||
fontSize = AppDimensions.sosTextSize,
|
||||
fontWeight = FontWeight.Bold,
|
||||
color = if (sosActive) SimpleTheme.colorScheme.primary else SimpleTheme.colorScheme.onSurface
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
internal fun StroboscopeButton(
|
||||
stroboscopeActive: Boolean,
|
||||
onStroboscopeButtonPress: () -> Unit,
|
||||
) {
|
||||
SmallButton(
|
||||
painter = painterResource(id = R.drawable.ic_stroboscope_vector),
|
||||
contentDescription = stringResource(id = R.string.stroboscope),
|
||||
isActive = stroboscopeActive,
|
||||
onPress = onStroboscopeButtonPress
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
internal fun MainScreenSlidersSection(
|
||||
showBrightnessBar: Boolean,
|
||||
brightnessBarValue: Float,
|
||||
onBrightnessBarValueChange: (Float) -> Unit,
|
||||
showStroboscopeBar: Boolean,
|
||||
stroboscopeBarValue: Float,
|
||||
onStroboscopeBarValueChange: (Float) -> Unit,
|
||||
) {
|
||||
val dimens = SimpleTheme.dimens
|
||||
val sliderModifier = remember {
|
||||
Modifier
|
||||
.padding(horizontal = dimens.padding.extraLarge)
|
||||
.padding(top = 24.dp, bottom = 40.dp)
|
||||
.size(width = AppDimensions.seekbarWidth, height = AppDimensions.seekbarHeight)
|
||||
}
|
||||
|
||||
if (showBrightnessBar) {
|
||||
Slider(
|
||||
modifier = sliderModifier,
|
||||
value = brightnessBarValue,
|
||||
onValueChange = onBrightnessBarValueChange
|
||||
)
|
||||
}
|
||||
|
||||
if (showStroboscopeBar) {
|
||||
Slider(
|
||||
modifier = sliderModifier,
|
||||
value = stroboscopeBarValue,
|
||||
onValueChange = onStroboscopeBarValueChange
|
||||
)
|
||||
}
|
||||
|
||||
if (!showBrightnessBar && !showStroboscopeBar) {
|
||||
Spacer(
|
||||
modifier = sliderModifier,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun SmallButton(
|
||||
painter: Painter,
|
||||
contentDescription: String,
|
||||
isActive: Boolean,
|
||||
onPress: () -> Unit
|
||||
) {
|
||||
Icon(
|
||||
modifier = Modifier
|
||||
.size(AppDimensions.smallerButtonSize)
|
||||
.padding(vertical = SimpleTheme.dimens.padding.large)
|
||||
.clickable(
|
||||
indication = null,
|
||||
interactionSource = rememberMutableInteractionSource(),
|
||||
onClick = onPress
|
||||
),
|
||||
painter = painter,
|
||||
contentDescription = contentDescription,
|
||||
tint = if (isActive) SimpleTheme.colorScheme.primary else SimpleTheme.colorScheme.onSurface
|
||||
)
|
||||
}
|
||||
|
||||
private fun buildActionMenu(
|
||||
showMoreApps: Boolean,
|
||||
openSettings: () -> Unit,
|
||||
openAbout: () -> Unit,
|
||||
openSleepTimer: () -> Unit,
|
||||
moreAppsFromUs: () -> Unit,
|
||||
): ImmutableList<ActionItem> {
|
||||
val settings =
|
||||
ActionItem(com.simplemobiletools.commons.R.string.settings, icon = Icons.Filled.Settings, doAction = openSettings, overflowMode = OverflowMode.NEVER_OVERFLOW)
|
||||
val about = ActionItem(com.simplemobiletools.commons.R.string.about, icon = Icons.Outlined.Info, doAction = openAbout, overflowMode = OverflowMode.NEVER_OVERFLOW)
|
||||
val sleepTimer = ActionItem(com.simplemobiletools.commons.R.string.sleep_timer, doAction = openSleepTimer, overflowMode = OverflowMode.ALWAYS_OVERFLOW)
|
||||
val list = mutableListOf(settings, about, sleepTimer)
|
||||
if (showMoreApps) {
|
||||
list += ActionItem(com.simplemobiletools.commons.R.string.more_apps_from_us, doAction = moreAppsFromUs, overflowMode = OverflowMode.ALWAYS_OVERFLOW)
|
||||
}
|
||||
return list.toImmutableList()
|
||||
}
|
||||
|
||||
@Composable
|
||||
@MyDevices
|
||||
internal fun MainScreenPreview() {
|
||||
AppThemeSurface {
|
||||
MainScreen(
|
||||
flashlightButton = {
|
||||
FlashlightButton(
|
||||
onFlashlightPress = {},
|
||||
flashlightActive = true,
|
||||
)
|
||||
},
|
||||
brightDisplayButton = {
|
||||
BrightDisplayButton(
|
||||
onBrightDisplayPress = {}
|
||||
)
|
||||
},
|
||||
sosButton = {
|
||||
SosButton(
|
||||
sosActive = false,
|
||||
onSosButtonPress = {},
|
||||
)
|
||||
},
|
||||
stroboscopeButton = {
|
||||
StroboscopeButton(
|
||||
stroboscopeActive = false,
|
||||
onStroboscopeButtonPress = {},
|
||||
)
|
||||
},
|
||||
slidersSection = {
|
||||
MainScreenSlidersSection(
|
||||
showBrightnessBar = false,
|
||||
brightnessBarValue = 0f,
|
||||
onBrightnessBarValueChange = {},
|
||||
showStroboscopeBar = false,
|
||||
stroboscopeBarValue = 0f,
|
||||
onStroboscopeBarValueChange = {},
|
||||
)
|
||||
},
|
||||
sleepTimer = {
|
||||
AnimatedSleepTimer(
|
||||
timerText = "00:00",
|
||||
timerVisible = true,
|
||||
onTimerClosePress = {},
|
||||
)
|
||||
},
|
||||
showMoreApps = true,
|
||||
openSettings = {},
|
||||
openAbout = {},
|
||||
moreAppsFromUs = {},
|
||||
openSleepTimer = {}
|
||||
)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,143 @@
|
|||
package com.simplemobiletools.flashlight.screens
|
||||
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import com.simplemobiletools.commons.compose.extensions.MyDevices
|
||||
import com.simplemobiletools.commons.compose.lists.SimpleColumnScaffold
|
||||
import com.simplemobiletools.commons.compose.settings.*
|
||||
import com.simplemobiletools.commons.compose.theme.AppThemeSurface
|
||||
import com.simplemobiletools.commons.compose.theme.SimpleTheme
|
||||
import com.simplemobiletools.flashlight.R
|
||||
|
||||
@Composable
|
||||
internal fun SettingsScreen(
|
||||
colorCustomizationSection: @Composable () -> Unit,
|
||||
generalSection: @Composable () -> Unit,
|
||||
goBack: () -> Unit,
|
||||
) {
|
||||
SimpleColumnScaffold(title = stringResource(id = com.simplemobiletools.commons.R.string.settings), goBack = goBack) {
|
||||
SettingsGroup(title = {
|
||||
SettingsTitleTextComponent(text = stringResource(id = com.simplemobiletools.commons.R.string.color_customization))
|
||||
}) {
|
||||
colorCustomizationSection()
|
||||
}
|
||||
SettingsHorizontalDivider()
|
||||
SettingsGroup(title = {
|
||||
SettingsTitleTextComponent(text = stringResource(id = com.simplemobiletools.commons.R.string.general_settings))
|
||||
}) {
|
||||
generalSection()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
internal fun ColorCustomizationSettingsSection(
|
||||
customizeColors: () -> Unit,
|
||||
customizeWidgetColors: () -> Unit,
|
||||
) {
|
||||
SettingsPreferenceComponent(
|
||||
label = stringResource(id = com.simplemobiletools.commons.R.string.customize_colors),
|
||||
doOnPreferenceClick = customizeColors,
|
||||
)
|
||||
SettingsPreferenceComponent(
|
||||
label = stringResource(id = com.simplemobiletools.commons.R.string.customize_widget_colors),
|
||||
doOnPreferenceClick = customizeWidgetColors
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
internal fun GeneralSettingsSection(
|
||||
showUseEnglish: Boolean,
|
||||
useEnglishChecked: Boolean,
|
||||
showDisplayLanguage: Boolean,
|
||||
displayLanguage: String,
|
||||
turnFlashlightOnStartupChecked: Boolean,
|
||||
forcePortraitModeChecked: Boolean,
|
||||
showBrightDisplayButtonChecked: Boolean,
|
||||
showSosButtonChecked: Boolean,
|
||||
showStroboscopeButtonChecked: Boolean,
|
||||
onUseEnglishPress: (Boolean) -> Unit,
|
||||
onSetupLanguagePress: () -> Unit,
|
||||
onTurnFlashlightOnStartupPress: (Boolean) -> Unit,
|
||||
onForcePortraitModePress: (Boolean) -> Unit,
|
||||
onShowBrightDisplayButtonPress: (Boolean) -> Unit,
|
||||
onShowSosButtonPress: (Boolean) -> Unit,
|
||||
onShowStroboscopeButtonPress: (Boolean) -> Unit,
|
||||
) {
|
||||
if (showUseEnglish) {
|
||||
SettingsCheckBoxComponent(
|
||||
label = stringResource(id = com.simplemobiletools.commons.R.string.use_english_language),
|
||||
initialValue = useEnglishChecked,
|
||||
onChange = onUseEnglishPress
|
||||
)
|
||||
}
|
||||
if (showDisplayLanguage) {
|
||||
SettingsPreferenceComponent(
|
||||
label = stringResource(id = com.simplemobiletools.commons.R.string.language),
|
||||
value = displayLanguage,
|
||||
doOnPreferenceClick = onSetupLanguagePress
|
||||
)
|
||||
}
|
||||
SettingsCheckBoxComponent(
|
||||
label = stringResource(id = R.string.turn_flashlight_on),
|
||||
initialValue = turnFlashlightOnStartupChecked,
|
||||
onChange = onTurnFlashlightOnStartupPress
|
||||
)
|
||||
SettingsCheckBoxComponent(
|
||||
label = stringResource(id = com.simplemobiletools.commons.R.string.force_portrait_mode),
|
||||
initialValue = forcePortraitModeChecked,
|
||||
onChange = onForcePortraitModePress
|
||||
)
|
||||
SettingsCheckBoxComponent(
|
||||
label = stringResource(id = R.string.show_bright_display),
|
||||
initialValue = showBrightDisplayButtonChecked,
|
||||
onChange = onShowBrightDisplayButtonPress
|
||||
)
|
||||
SettingsCheckBoxComponent(
|
||||
label = stringResource(id = R.string.show_sos),
|
||||
initialValue = showSosButtonChecked,
|
||||
onChange = onShowSosButtonPress
|
||||
)
|
||||
SettingsCheckBoxComponent(
|
||||
label = stringResource(id = R.string.show_stroboscope),
|
||||
initialValue = showStroboscopeButtonChecked,
|
||||
onChange = onShowStroboscopeButtonPress
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
@MyDevices
|
||||
private fun SettingsScreenPreview() {
|
||||
AppThemeSurface {
|
||||
SettingsScreen(
|
||||
colorCustomizationSection = {
|
||||
ColorCustomizationSettingsSection(
|
||||
customizeColors = {},
|
||||
customizeWidgetColors = {},
|
||||
)
|
||||
},
|
||||
generalSection = {
|
||||
GeneralSettingsSection(
|
||||
useEnglishChecked = true,
|
||||
showUseEnglish = true,
|
||||
showDisplayLanguage = true,
|
||||
displayLanguage = "English",
|
||||
turnFlashlightOnStartupChecked = false,
|
||||
forcePortraitModeChecked = true,
|
||||
showBrightDisplayButtonChecked = true,
|
||||
showSosButtonChecked = true,
|
||||
showStroboscopeButtonChecked = true,
|
||||
onUseEnglishPress = {},
|
||||
onSetupLanguagePress = {},
|
||||
onTurnFlashlightOnStartupPress = {},
|
||||
onForcePortraitModePress = {},
|
||||
onShowBrightDisplayButtonPress = {},
|
||||
onShowSosButtonPress = {},
|
||||
onShowStroboscopeButtonPress = {},
|
||||
)
|
||||
},
|
||||
goBack = {},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,107 @@
|
|||
package com.simplemobiletools.flashlight.screens
|
||||
|
||||
import androidx.annotation.ColorInt
|
||||
import androidx.annotation.DrawableRes
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.foundation.shape.CircleShape
|
||||
import androidx.compose.material3.*
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.clip
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.SolidColor
|
||||
import androidx.compose.ui.graphics.painter.BrushPainter
|
||||
import androidx.compose.ui.graphics.toArgb
|
||||
import androidx.compose.ui.res.colorResource
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import com.simplemobiletools.commons.compose.extensions.MyDevices
|
||||
import com.simplemobiletools.commons.compose.theme.AppThemeSurface
|
||||
import com.simplemobiletools.commons.compose.theme.SimpleTheme
|
||||
import com.simplemobiletools.commons.extensions.adjustAlpha
|
||||
import com.simplemobiletools.flashlight.R
|
||||
import com.simplemobiletools.flashlight.helpers.AppDimensions
|
||||
|
||||
@Composable
|
||||
internal fun WidgetConfigureScreen(
|
||||
@DrawableRes
|
||||
widgetDrawable: Int,
|
||||
@ColorInt
|
||||
widgetColor: Int,
|
||||
widgetAlpha: Float,
|
||||
onSliderChanged: (Float) -> Unit,
|
||||
onColorPressed: () -> Unit,
|
||||
onSavePressed: () -> Unit
|
||||
) {
|
||||
Column(
|
||||
modifier = Modifier.fillMaxSize().safeDrawingPadding(),
|
||||
verticalArrangement = Arrangement.Bottom,
|
||||
) {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.padding(SimpleTheme.dimens.padding.extraLarge)
|
||||
.padding(bottom = SimpleTheme.dimens.padding.extraLarge)
|
||||
.fillMaxWidth()
|
||||
.weight(1f)
|
||||
) {
|
||||
Icon(
|
||||
modifier = Modifier
|
||||
.align(Alignment.Center)
|
||||
.size(AppDimensions.mainButtonSize),
|
||||
painter = painterResource(id = widgetDrawable),
|
||||
contentDescription = stringResource(id = R.string.bright_display),
|
||||
tint = Color(widgetColor.adjustAlpha(widgetAlpha))
|
||||
)
|
||||
}
|
||||
|
||||
Row {
|
||||
Icon(
|
||||
modifier = Modifier
|
||||
.size(AppDimensions.widgetColorPickerSize)
|
||||
.padding(SimpleTheme.dimens.padding.extraSmall)
|
||||
.clip(CircleShape)
|
||||
.clickable { onColorPressed() },
|
||||
painter = BrushPainter(SolidColor(Color(widgetColor))),
|
||||
contentDescription = stringResource(id = R.string.bright_display),
|
||||
tint = Color(widgetColor)
|
||||
)
|
||||
|
||||
Slider(
|
||||
value = widgetAlpha,
|
||||
onValueChange = onSliderChanged,
|
||||
modifier = Modifier
|
||||
.padding(start = SimpleTheme.dimens.padding.medium)
|
||||
.background(
|
||||
color = colorResource(id = com.simplemobiletools.commons.R.color.md_grey_white),
|
||||
shape = SimpleTheme.shapes.extraLarge
|
||||
)
|
||||
.padding(horizontal = SimpleTheme.dimens.padding.extraLarge)
|
||||
)
|
||||
}
|
||||
|
||||
Button(
|
||||
modifier = Modifier.align(Alignment.End),
|
||||
onClick = onSavePressed
|
||||
) {
|
||||
Text(text = stringResource(id = com.simplemobiletools.commons.R.string.ok))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
@MyDevices
|
||||
private fun WidgetBrightDisplayConfigureScreenPreview() {
|
||||
AppThemeSurface {
|
||||
WidgetConfigureScreen(
|
||||
widgetDrawable = R.drawable.ic_bright_display_vector,
|
||||
widgetColor = SimpleTheme.colorScheme.primary.toArgb(),
|
||||
widgetAlpha = 1f,
|
||||
onSliderChanged = {},
|
||||
onColorPressed = {},
|
||||
onSavePressed = {}
|
||||
)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,96 @@
|
|||
package com.simplemobiletools.flashlight.views
|
||||
|
||||
import androidx.compose.animation.AnimatedVisibility
|
||||
import androidx.compose.animation.fadeIn
|
||||
import androidx.compose.animation.fadeOut
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.border
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.IconButton
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.RectangleShape
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.simplemobiletools.commons.compose.extensions.MyDevices
|
||||
import com.simplemobiletools.commons.compose.theme.AppThemeSurface
|
||||
import com.simplemobiletools.commons.compose.theme.SimpleTheme
|
||||
import com.simplemobiletools.commons.compose.theme.divider_grey
|
||||
|
||||
@Composable
|
||||
internal fun SleepTimer(
|
||||
modifier: Modifier = Modifier,
|
||||
timerText: String,
|
||||
onCloseClick: () -> Unit
|
||||
) {
|
||||
Row(
|
||||
modifier = modifier
|
||||
.border(
|
||||
width = 1.dp,
|
||||
color = divider_grey,
|
||||
shape = RectangleShape
|
||||
)
|
||||
.background(SimpleTheme.colorScheme.surface)
|
||||
) {
|
||||
Text(
|
||||
modifier = Modifier
|
||||
.align(Alignment.CenterVertically)
|
||||
.padding(horizontal = SimpleTheme.dimens.padding.large),
|
||||
text = stringResource(id = com.simplemobiletools.commons.R.string.sleep_timer),
|
||||
color = SimpleTheme.colorScheme.onSurface
|
||||
)
|
||||
Text(
|
||||
modifier = Modifier.align(Alignment.CenterVertically),
|
||||
text = timerText,
|
||||
color = SimpleTheme.colorScheme.onSurface
|
||||
)
|
||||
IconButton(
|
||||
modifier = Modifier
|
||||
.align(Alignment.CenterVertically)
|
||||
.padding(SimpleTheme.dimens.padding.medium),
|
||||
onClick = onCloseClick
|
||||
) {
|
||||
Icon(
|
||||
painter = painterResource(id = com.simplemobiletools.commons.R.drawable.ic_cross_vector),
|
||||
contentDescription = stringResource(id = com.simplemobiletools.commons.R.string.close),
|
||||
tint = SimpleTheme.colorScheme.onSurface
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
internal fun AnimatedSleepTimer(
|
||||
modifier: Modifier = Modifier,
|
||||
timerText: String,
|
||||
timerVisible: Boolean,
|
||||
onTimerClosePress: () -> Unit
|
||||
) {
|
||||
AnimatedVisibility(
|
||||
modifier = modifier,
|
||||
visible = timerVisible && timerText.isNotEmpty(),
|
||||
enter = fadeIn(),
|
||||
exit = fadeOut()
|
||||
) {
|
||||
SleepTimer(
|
||||
timerText = timerText,
|
||||
onCloseClick = onTimerClosePress
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
@MyDevices
|
||||
internal fun SleepTimerPreview() {
|
||||
AppThemeSurface {
|
||||
SleepTimer(
|
||||
timerText = "00:00",
|
||||
onCloseClick = {}
|
||||
)
|
||||
}
|
||||
}
|
Before Width: | Height: | Size: 1.3 KiB |
Before Width: | Height: | Size: 3.1 KiB |
Before Width: | Height: | Size: 1.3 KiB |
Before Width: | Height: | Size: 2.7 KiB After Width: | Height: | Size: 2.7 KiB |
Before Width: | Height: | Size: 4.0 KiB After Width: | Height: | Size: 4.0 KiB |
Before Width: | Height: | Size: 1.6 KiB |
Before Width: | Height: | Size: 4.3 KiB |
Before Width: | Height: | Size: 1.7 KiB |
Before Width: | Height: | Size: 2.7 KiB |
Before Width: | Height: | Size: 7.8 KiB |
Before Width: | Height: | Size: 3.9 KiB |
Before Width: | Height: | Size: 11 KiB |
Before Width: | Height: | Size: 4.6 KiB |
|
@ -0,0 +1,3 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android" android:width="192dp" android:height="192dp" android:viewportWidth="192" android:viewportHeight="192">
|
||||
<path android:fillColor="#FFFFFFFF" android:fillType="evenOdd" android:pathData="M47.83 20.85c1.15-2.49 3.16-4.5 5.65-5.65 2.49-1.15 7.08-1.06 9.85-1.06h66.08c2.76 0 7.36-0.09 9.85 1.06 2.49 1.15 4.5 3.16 5.65 5.65 1.15 2.49 1.06 7.08 1.06 9.85l-0.01 130.61c0 2.76 0.09 7.36-1.06 9.85-1.15 2.49-3.16 4.5-5.65 5.65-2.49 1.15-7.08 1.06-9.85 1.06l-66.08-0.01c-2.76 0-7.36 0.09-9.85-1.06-2.49-1.15-4.5-3.16-5.65-5.65-1.15-2.49-1.06-7.08-1.06-9.85V30.69c0-2.76-0.09-7.36 1.06-9.85zm10.13 7.89c0.42-0.56 0.92-1.06 1.48-1.48 2.16-1.64 6.89-1.57 9.66-1.57h54.53c2.76 0 7.5-0.08 9.66 1.57 0.56 0.42 1.06 0.92 1.48 1.48 1.64 2.16 1.57 6.89 1.57 9.66l-0.01 113.27c0 2.76 0.08 7.5-1.57 9.66-0.42 0.56-0.92 1.06-1.48 1.48-2.16 1.64-6.89 1.57-9.66 1.57H69.1c-2.76 0-7.5 0.08-9.66-1.57-0.56-0.42-1.06-0.92-1.48-1.48-1.64-2.16-1.57-6.89-1.57-9.66L56.4 38.4c0-2.76-0.08-7.5 1.57-9.66zm13.07 7.55h50.67a5 5 45 0 1 5 5v107.5a5 5 135 0 1-5 5H71.03a5 5 45 0 1-5-5V41.29a5 5 135 0 1 5-5zM16.99 47.27l14.37 5.18a5 5 64.83 0 1 3.01 6.4 4.56 4.56 160.65 0 1-6.09 2.14l-14.37-5.18a5 5 64.83 0 1-3.01-6.4 4.56 4.56 160.65 0 1 6.09-2.14zm158.66 0l-14.37 5.18a5 5 115.17 0 0-3.01 6.4 4.56 4.56 19.35 0 0 6.09 2.14l14.37-5.18a5 5 115.17 0 0 3.01-6.4 4.56 4.56 19.35 0 0-6.09-2.14zm-144.29 84l-14.37 5.18a5 5 25.17 0 1-6.4-3.01 4.56 4.56 121 0 1 3.32-5.53l14.37-5.18a5 5 25.17 0 1 6.4 3.01 4.56 4.56 121 0 1-3.32 5.53zm144.27 5.18l-14.37-5.18a5 5 64.83 0 1-3.01-6.4 4.56 4.56 160.65 0 1 6.09-2.14l14.37 5.18a5 5 64.82 0 1 3.01 6.4 4.56 4.56 160.65 0 1-6.09 2.14zm-7.33-40.04h15.27a5 5 135 0 0 5-5 4.56 4.56 39.18 0 0-5-4.07H168.3a5 5 135 0 0-5 5 4.56 4.56 39.18 0 0 5 4.07zm-144.6 0H8.43a5 5 45 0 1-5-5 4.56 4.56 140.82 0 1 5-4.07H23.7a5 5 45 0 1 5 5 4.56 4.56 140.82 0 1-5 4.07z"/>
|
||||
</vector>
|
|
@ -0,0 +1,3 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android" android:width="192dp" android:height="192dp" android:viewportWidth="192" android:viewportHeight="192">
|
||||
<path android:fillColor="#FFFFFFFF" android:fillType="evenOdd" android:pathData="M100.17 30.03c0 2.05-1.66 3.72-3.72 3.72-2.05 0-3.72-1.66-3.72-3.72V13.31c0-2.05 1.66-3.72 3.72-3.72 2.05 0 3.72 1.66 3.72 3.72zM71.24 20c1.69-0.99 3.87-0.42 4.86 1.27l6.58 11.24c0.99 1.69 0.42 3.87-1.27 4.86-1.69 0.99-3.87 0.42-4.86-1.27l-6.58-11.25c-0.99-1.69-0.42-3.87 1.27-4.86zm49.59 0c-1.69-0.99-3.87-0.42-4.86 1.27l-6.58 11.24c-0.99 1.69-0.42 3.87 1.27 4.86 1.69 0.99 3.87 0.42 4.86-1.27l6.58-11.24c0.99-1.69 0.42-3.87-1.27-4.86zm-41.5 66.61c-0.6 1.78-0.93 3.69-0.93 5.68v72.47c0 9.75 7.9 17.65 17.65 17.65 9.75 0 17.65-7.9 17.65-17.65l0.01-72.48c0-2.01-0.34-3.94-0.96-5.74 7.69-4.02 12.93-10.71 15.82-17.95l0.52-1.53 0.01-0.02c0.57-1.65 0.9-2.6 1.33-4.95 1.1-6.04 0.93-7.9 0.46-8.83-2.52-5.05-15.6-9.29-34.84-9.29-19.24 0-35.31 5.04-35.31 10.69v0.42c0 1.69-0.01 3.26 0.47 6.09 0.46 2.79 0.93 4.18 2.32 7.43 3.24 7.55 8.33 14.11 15.8 18.02zm16.72 14.04c-3.59 0-6.5 2.91-6.5 6.5v9.29c0 3.59 2.91 6.5 6.5 6.5s6.5-2.91 6.5-6.5v-9.29c0-3.59-2.91-6.5-6.5-6.5zm27.88-46c-4.65 2.79-12.69 5.11-28.34 5.11s-23.23-2.32-28.34-5.11c3.25-2.32 12.69-5.11 28.34-5.11s25.09 3.25 28.34 5.11z"/>
|
||||
</vector>
|
|
@ -0,0 +1,3 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android" android:width="192dp" android:height="192dp" android:viewportWidth="192" android:viewportHeight="192">
|
||||
<path android:fillColor="#FFFFFFFF" android:fillType="evenOdd" android:pathData="M96 42.99c9.59 0 17.37-7.78 17.37-17.37S105.59 8.25 96 8.25s-17.37 7.77-17.37 17.37c0 9.59 7.78 17.37 17.37 17.37zm0 140.76c9.59 0 17.37-7.78 17.37-17.37s-7.78-17.37-17.37-17.37-17.37 7.78-17.37 17.37 7.78 17.37 17.37 17.37zm67.64-137.11c0 9.59-7.78 17.37-17.37 17.37s-17.37-7.78-17.37-17.37 7.78-17.37 17.37-17.37 17.37 7.78 17.37 17.37zM45.73 64.01c9.59 0 17.37-7.78 17.37-17.37s-7.78-17.37-17.37-17.37-17.37 7.78-17.37 17.37 7.78 17.37 17.37 17.37zm117.91 81.35c0 9.59-7.78 17.37-17.37 17.37s-17.37-7.78-17.37-17.37 7.78-17.37 17.37-17.37 17.37 7.78 17.37 17.37zM45.73 162.72c9.59 0 17.37-7.78 17.37-17.37s-7.78-17.37-17.37-17.37-17.37 7.78-17.37 17.37 7.78 17.37 17.37 17.37zM183.75 96c0 9.59-7.78 17.37-17.37 17.37s-17.37-7.78-17.37-17.37 7.78-17.37 17.37-17.37 17.37 7.78 17.37 17.37zM25.62 113.37c9.59 0 17.37-7.78 17.37-17.37s-7.78-17.37-17.37-17.37S8.25 86.41 8.25 96s7.78 17.37 17.37 17.37z"/>
|
||||
</vector>
|
|
@ -7,10 +7,10 @@
|
|||
</item>
|
||||
|
||||
<item
|
||||
android:bottom="@dimen/normal_margin"
|
||||
android:drawable="@drawable/ic_bright_display"
|
||||
android:left="@dimen/normal_margin"
|
||||
android:right="@dimen/normal_margin"
|
||||
android:top="@dimen/normal_margin" />
|
||||
android:bottom="@dimen/shortcut_padding"
|
||||
android:drawable="@drawable/ic_bright_display_vector"
|
||||
android:left="@dimen/shortcut_padding"
|
||||
android:right="@dimen/shortcut_padding"
|
||||
android:top="@dimen/shortcut_padding" />
|
||||
|
||||
</layer-list>
|
||||
|
|
|
@ -1,22 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:id="@+id/bright_display_holder"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<FrameLayout
|
||||
android:id="@+id/bright_display"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:background="@android:color/white" />
|
||||
|
||||
<android.widget.TextView
|
||||
android:id="@+id/bright_display_change_color"
|
||||
style="@style/StrokeButtonStyle"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_centerInParent="true"
|
||||
android:alpha="0.5"
|
||||
android:text="@string/change_color" />
|
||||
|
||||
</RelativeLayout>
|
|
@ -1,110 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:id="@+id/main_coordinator"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<com.google.android.material.appbar.AppBarLayout
|
||||
android:id="@+id/main_app_bar_layout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<com.google.android.material.appbar.MaterialToolbar
|
||||
android:id="@+id/main_toolbar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="?attr/actionBarSize"
|
||||
android:background="@color/color_primary"
|
||||
app:menu="@menu/menu"
|
||||
app:title="@string/app_launcher_name"
|
||||
app:titleTextAppearance="@style/AppTheme.ActionBar.TitleTextStyle" />
|
||||
|
||||
</com.google.android.material.appbar.AppBarLayout>
|
||||
|
||||
<androidx.core.widget.NestedScrollView
|
||||
android:id="@+id/main_scrollview"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:fillViewport="true"
|
||||
android:scrollbars="none"
|
||||
app:layout_behavior="@string/appbar_scrolling_view_behavior">
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:id="@+id/main_holder"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/flashlight_btn"
|
||||
android:layout_width="@dimen/main_button_size"
|
||||
android:layout_height="@dimen/main_button_size"
|
||||
android:layout_marginTop="@dimen/normal_margin"
|
||||
android:layout_marginBottom="@dimen/normal_margin"
|
||||
android:background="@drawable/ic_flashlight"
|
||||
app:layout_constraintBottom_toTopOf="@+id/bright_display_btn"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintHorizontal_bias="0.5"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/bright_display_btn"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="@dimen/normal_margin"
|
||||
android:layout_marginBottom="@dimen/normal_margin"
|
||||
android:background="@drawable/ic_bright_display"
|
||||
android:padding="@dimen/activity_margin"
|
||||
app:layout_constraintBottom_toTopOf="@+id/sos_btn"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintHorizontal_bias="0.5"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/flashlight_btn" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/sos_btn"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="@dimen/normal_margin"
|
||||
android:layout_marginBottom="@dimen/normal_margin"
|
||||
android:background="?attr/selectableItemBackgroundBorderless"
|
||||
android:padding="@dimen/activity_margin"
|
||||
android:text="SOS"
|
||||
android:textSize="@dimen/sos_text_size"
|
||||
android:textStyle="bold"
|
||||
app:layout_constraintBottom_toTopOf="@+id/stroboscope_btn"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintHorizontal_bias="0.5"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/bright_display_btn" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/stroboscope_btn"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="@dimen/normal_margin"
|
||||
android:background="@drawable/ic_stroboscope"
|
||||
android:padding="@dimen/activity_margin"
|
||||
app:layout_constraintBottom_toTopOf="@+id/stroboscope_bar"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintHorizontal_bias="0.5"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/sos_btn" />
|
||||
|
||||
<com.simplemobiletools.commons.views.MySeekBar
|
||||
android:id="@+id/stroboscope_bar"
|
||||
android:layout_width="@dimen/seekbar_width"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="@dimen/activity_margin"
|
||||
android:paddingTop="@dimen/medium_margin"
|
||||
android:paddingBottom="@dimen/medium_margin"
|
||||
android:visibility="invisible"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintHorizontal_bias="0.5"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/stroboscope_btn" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
</androidx.core.widget.NestedScrollView>
|
||||
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
|
@ -1,239 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:id="@+id/settings_coordinator"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<com.google.android.material.appbar.AppBarLayout
|
||||
android:id="@+id/settings_app_bar_layout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<com.google.android.material.appbar.MaterialToolbar
|
||||
android:id="@+id/settings_toolbar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="?attr/actionBarSize"
|
||||
android:background="@color/color_primary"
|
||||
app:title="@string/settings"
|
||||
app:titleTextAppearance="@style/AppTheme.ActionBar.TitleTextStyle" />
|
||||
|
||||
</com.google.android.material.appbar.AppBarLayout>
|
||||
|
||||
<androidx.core.widget.NestedScrollView
|
||||
android:id="@+id/settings_nested_scrollview"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:fillViewport="true"
|
||||
android:scrollbars="none"
|
||||
app:layout_behavior="@string/appbar_scrolling_view_behavior">
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/settings_holder"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/settings_color_customization_label"
|
||||
style="@style/SettingsSectionLabelStyle"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/color_customization" />
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/settings_color_customization_holder"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="@dimen/medium_margin"
|
||||
android:background="@drawable/section_holder_stroke"
|
||||
android:orientation="vertical">
|
||||
|
||||
<RelativeLayout
|
||||
android:id="@+id/settings_customize_colors_holder"
|
||||
style="@style/SettingsHolderTextViewOneLinerStyle"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@drawable/ripple_top_corners">
|
||||
|
||||
<com.simplemobiletools.commons.views.MyTextView
|
||||
android:id="@+id/settings_customize_colors_label"
|
||||
style="@style/SettingsTextLabelStyle"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/customize_colors" />
|
||||
|
||||
</RelativeLayout>
|
||||
|
||||
<RelativeLayout
|
||||
android:id="@+id/settings_customize_widget_colors_holder"
|
||||
style="@style/SettingsHolderTextViewStyle"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@drawable/ripple_bottom_corners">
|
||||
|
||||
<com.simplemobiletools.commons.views.MyTextView
|
||||
android:id="@+id/settings_customize_widget_colors_label"
|
||||
style="@style/SettingsTextLabelStyle"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/customize_widget_colors" />
|
||||
|
||||
</RelativeLayout>
|
||||
</LinearLayout>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/settings_general_settings_label"
|
||||
style="@style/SettingsSectionLabelStyle"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/general_settings" />
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/settings_general_settings_holder"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="@dimen/medium_margin"
|
||||
android:background="@drawable/section_holder_stroke"
|
||||
android:orientation="vertical">
|
||||
|
||||
<RelativeLayout
|
||||
android:id="@+id/settings_purchase_thank_you_holder"
|
||||
style="@style/SettingsHolderTextViewStyle"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@drawable/ripple_top_corners">
|
||||
|
||||
<com.simplemobiletools.commons.views.MyTextView
|
||||
android:id="@+id/settings_purchase_thank_you"
|
||||
style="@style/SettingsTextLabelStyle"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/purchase_simple_thank_you" />
|
||||
|
||||
</RelativeLayout>
|
||||
|
||||
<RelativeLayout
|
||||
android:id="@+id/settings_use_english_holder"
|
||||
style="@style/SettingsHolderCheckboxStyle"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@drawable/ripple_background">
|
||||
|
||||
<com.simplemobiletools.commons.views.MyAppCompatCheckbox
|
||||
android:id="@+id/settings_use_english"
|
||||
style="@style/SettingsCheckboxStyle"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/use_english_language" />
|
||||
|
||||
</RelativeLayout>
|
||||
|
||||
<RelativeLayout
|
||||
android:id="@+id/settings_language_holder"
|
||||
style="@style/SettingsHolderTextViewStyle"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@drawable/ripple_background">
|
||||
|
||||
<com.simplemobiletools.commons.views.MyTextView
|
||||
android:id="@+id/settings_language_label"
|
||||
style="@style/SettingsTextLabelStyle"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/language" />
|
||||
|
||||
<com.simplemobiletools.commons.views.MyTextView
|
||||
android:id="@+id/settings_language"
|
||||
style="@style/SettingsTextValueStyle"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_below="@+id/settings_language_label"
|
||||
tools:text="English" />
|
||||
|
||||
</RelativeLayout>
|
||||
|
||||
<RelativeLayout
|
||||
android:id="@+id/settings_turn_flashlight_on_holder"
|
||||
style="@style/SettingsHolderCheckboxStyle"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@drawable/ripple_background">
|
||||
|
||||
<com.simplemobiletools.commons.views.MyAppCompatCheckbox
|
||||
android:id="@+id/settings_turn_flashlight_on"
|
||||
style="@style/SettingsCheckboxStyle"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/turn_flashlight_on" />
|
||||
|
||||
</RelativeLayout>
|
||||
|
||||
<RelativeLayout
|
||||
android:id="@+id/settings_force_portrait_holder"
|
||||
style="@style/SettingsHolderCheckboxStyle"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@drawable/ripple_background">
|
||||
|
||||
<com.simplemobiletools.commons.views.MyAppCompatCheckbox
|
||||
android:id="@+id/settings_force_portrait"
|
||||
style="@style/SettingsCheckboxStyle"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/force_portrait_mode" />
|
||||
|
||||
</RelativeLayout>
|
||||
|
||||
<RelativeLayout
|
||||
android:id="@+id/settings_bright_display_holder"
|
||||
style="@style/SettingsHolderCheckboxStyle"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@drawable/ripple_background">
|
||||
|
||||
<com.simplemobiletools.commons.views.MyAppCompatCheckbox
|
||||
android:id="@+id/settings_bright_display"
|
||||
style="@style/SettingsCheckboxStyle"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/show_bright_display" />
|
||||
|
||||
</RelativeLayout>
|
||||
|
||||
<RelativeLayout
|
||||
android:id="@+id/settings_sos_holder"
|
||||
style="@style/SettingsHolderCheckboxStyle"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@drawable/ripple_background">
|
||||
|
||||
<com.simplemobiletools.commons.views.MyAppCompatCheckbox
|
||||
android:id="@+id/settings_sos"
|
||||
style="@style/SettingsCheckboxStyle"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/show_sos" />
|
||||
|
||||
</RelativeLayout>
|
||||
|
||||
<RelativeLayout
|
||||
android:id="@+id/settings_stroboscope_holder"
|
||||
style="@style/SettingsHolderCheckboxStyle"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@drawable/ripple_bottom_corners">
|
||||
|
||||
<com.simplemobiletools.commons.views.MyAppCompatCheckbox
|
||||
android:id="@+id/settings_stroboscope"
|
||||
style="@style/SettingsCheckboxStyle"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/show_stroboscope" />
|
||||
|
||||
</RelativeLayout>
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
</androidx.core.widget.NestedScrollView>
|
||||
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
|
@ -1,83 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:id="@+id/config_bright_display_coordinator"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<com.google.android.material.appbar.AppBarLayout
|
||||
android:id="@+id/config_bright_display_app_bar_layout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<com.google.android.material.appbar.MaterialToolbar
|
||||
android:id="@+id/config_bright_display_toolbar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="?attr/actionBarSize"
|
||||
android:background="@color/color_primary"
|
||||
app:title="@string/app_launcher_name"
|
||||
app:titleTextAppearance="@style/AppTheme.ActionBar.TitleTextStyle" />
|
||||
|
||||
</com.google.android.material.appbar.AppBarLayout>
|
||||
|
||||
<RelativeLayout
|
||||
android:id="@+id/config_bright_display_holder"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_centerHorizontal="true"
|
||||
android:layout_margin="@dimen/activity_margin">
|
||||
|
||||
<RelativeLayout
|
||||
android:id="@+id/config_bright_display_wrapper"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_above="@+id/config_widget_color"
|
||||
android:layout_marginBottom="@dimen/activity_margin"
|
||||
android:gravity="center">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/config_image"
|
||||
android:layout_width="@dimen/main_button_size"
|
||||
android:layout_height="@dimen/main_button_size"
|
||||
android:background="@drawable/ic_bright_display" />
|
||||
|
||||
</RelativeLayout>
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/config_widget_color"
|
||||
android:layout_width="@dimen/widget_colorpicker_size"
|
||||
android:layout_height="@dimen/widget_colorpicker_size"
|
||||
android:layout_above="@+id/config_save"
|
||||
android:layout_margin="@dimen/tiny_margin" />
|
||||
|
||||
<RelativeLayout
|
||||
android:id="@+id/config_widget_seekbar_holder"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_alignTop="@+id/config_widget_color"
|
||||
android:layout_alignBottom="@+id/config_widget_color"
|
||||
android:layout_marginStart="@dimen/medium_margin"
|
||||
android:layout_toEndOf="@+id/config_widget_color"
|
||||
android:background="@drawable/widget_config_seekbar_background">
|
||||
|
||||
<com.simplemobiletools.commons.views.MySeekBar
|
||||
android:id="@+id/config_widget_seekbar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_centerVertical="true"
|
||||
android:paddingStart="@dimen/activity_margin"
|
||||
android:paddingEnd="@dimen/activity_margin" />
|
||||
</RelativeLayout>
|
||||
|
||||
<Button
|
||||
android:id="@+id/config_save"
|
||||
style="@style/MyWidgetConfigSaveStyle"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignParentEnd="true"
|
||||
android:layout_alignParentBottom="true"
|
||||
android:layout_marginTop="@dimen/tiny_margin"
|
||||
android:text="@string/ok" />
|
||||
|
||||
</RelativeLayout>
|
||||
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
|
@ -1,82 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:id="@+id/config_torch_coordinator"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<com.google.android.material.appbar.AppBarLayout
|
||||
android:id="@+id/config_torch_app_bar_layout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<com.google.android.material.appbar.MaterialToolbar
|
||||
android:id="@+id/config_torch_toolbar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="?attr/actionBarSize"
|
||||
android:background="@color/color_primary"
|
||||
app:title="@string/app_launcher_name"
|
||||
app:titleTextAppearance="@style/AppTheme.ActionBar.TitleTextStyle" />
|
||||
|
||||
</com.google.android.material.appbar.AppBarLayout>
|
||||
|
||||
<RelativeLayout
|
||||
android:id="@+id/config_torch_holder"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_centerHorizontal="true"
|
||||
android:layout_margin="@dimen/activity_margin">
|
||||
|
||||
<RelativeLayout
|
||||
android:id="@+id/config_torch_wrapper"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_above="@+id/config_widget_color"
|
||||
android:layout_marginBottom="@dimen/activity_margin"
|
||||
android:gravity="center">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/config_image"
|
||||
android:layout_width="@dimen/main_button_size"
|
||||
android:layout_height="@dimen/main_button_size"
|
||||
android:background="@drawable/ic_flashlight" />
|
||||
</RelativeLayout>
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/config_widget_color"
|
||||
android:layout_width="@dimen/widget_colorpicker_size"
|
||||
android:layout_height="@dimen/widget_colorpicker_size"
|
||||
android:layout_above="@+id/config_save"
|
||||
android:layout_margin="@dimen/tiny_margin" />
|
||||
|
||||
<RelativeLayout
|
||||
android:id="@+id/config_widget_seekbar_holder"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_alignTop="@+id/config_widget_color"
|
||||
android:layout_alignBottom="@+id/config_widget_color"
|
||||
android:layout_marginStart="@dimen/medium_margin"
|
||||
android:layout_toEndOf="@+id/config_widget_color"
|
||||
android:background="@drawable/widget_config_seekbar_background">
|
||||
|
||||
<com.simplemobiletools.commons.views.MySeekBar
|
||||
android:id="@+id/config_widget_seekbar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_centerVertical="true"
|
||||
android:paddingStart="@dimen/activity_margin"
|
||||
android:paddingEnd="@dimen/activity_margin" />
|
||||
</RelativeLayout>
|
||||
|
||||
<Button
|
||||
android:id="@+id/config_save"
|
||||
style="@style/MyWidgetConfigSaveStyle"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignParentEnd="true"
|
||||
android:layout_alignParentBottom="true"
|
||||
android:layout_marginTop="@dimen/tiny_margin"
|
||||
android:text="@string/ok" />
|
||||
|
||||
</RelativeLayout>
|
||||
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
|
@ -1,14 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<menu xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||
<item
|
||||
android:id="@+id/settings"
|
||||
android:icon="@drawable/ic_settings_cog_vector"
|
||||
android:title="@string/settings"
|
||||
app:showAsAction="always" />
|
||||
<item
|
||||
android:id="@+id/about"
|
||||
android:icon="@drawable/ic_info_vector"
|
||||
android:title="@string/about"
|
||||
app:showAsAction="always" />
|
||||
</menu>
|
|
@ -1,5 +1,6 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<background android:drawable="@color/md_amber_700"/>
|
||||
<foreground android:drawable="@mipmap/ic_launcher_foreground"/>
|
||||
<background android:drawable="@color/md_amber_700" />
|
||||
<foreground android:drawable="@mipmap/ic_launcher_foreground" />
|
||||
<monochrome android:drawable="@drawable/ic_launcher_monochrome" />
|
||||
</adaptive-icon>
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<background android:drawable="@color/md_blue_700"/>
|
||||
<foreground android:drawable="@mipmap/ic_launcher_foreground"/>
|
||||
<background android:drawable="@color/md_blue_700" />
|
||||
<foreground android:drawable="@mipmap/ic_launcher_foreground" />
|
||||
<monochrome android:drawable="@drawable/ic_launcher_monochrome" />
|
||||
</adaptive-icon>
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<background android:drawable="@color/md_blue_grey_700"/>
|
||||
<foreground android:drawable="@mipmap/ic_launcher_foreground"/>
|
||||
<background android:drawable="@color/md_blue_grey_700" />
|
||||
<foreground android:drawable="@mipmap/ic_launcher_foreground" />
|
||||
<monochrome android:drawable="@drawable/ic_launcher_monochrome" />
|
||||
</adaptive-icon>
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<background android:drawable="@color/md_brown_700"/>
|
||||
<foreground android:drawable="@mipmap/ic_launcher_foreground"/>
|
||||
<background android:drawable="@color/md_brown_700" />
|
||||
<foreground android:drawable="@mipmap/ic_launcher_foreground" />
|
||||
<monochrome android:drawable="@drawable/ic_launcher_monochrome" />
|
||||
</adaptive-icon>
|
||||
|
|
|
@ -2,4 +2,5 @@
|
|||
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<background android:drawable="@color/md_cyan_700"/>
|
||||
<foreground android:drawable="@mipmap/ic_launcher_foreground"/>
|
||||
<monochrome android:drawable="@drawable/ic_launcher_monochrome" />
|
||||
</adaptive-icon>
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<background android:drawable="@color/md_deep_orange_700"/>
|
||||
<foreground android:drawable="@mipmap/ic_launcher_foreground"/>
|
||||
<background android:drawable="@color/md_deep_orange_700" />
|
||||
<foreground android:drawable="@mipmap/ic_launcher_foreground" />
|
||||
<monochrome android:drawable="@drawable/ic_launcher_monochrome" />
|
||||
</adaptive-icon>
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<background android:drawable="@color/md_deep_purple_700"/>
|
||||
<foreground android:drawable="@mipmap/ic_launcher_foreground"/>
|
||||
<background android:drawable="@color/md_deep_purple_700" />
|
||||
<foreground android:drawable="@mipmap/ic_launcher_foreground" />
|
||||
<monochrome android:drawable="@drawable/ic_launcher_monochrome" />
|
||||
</adaptive-icon>
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<background android:drawable="@color/md_green_700"/>
|
||||
<foreground android:drawable="@mipmap/ic_launcher_foreground"/>
|
||||
<background android:drawable="@color/md_green_700" />
|
||||
<foreground android:drawable="@mipmap/ic_launcher_foreground" />
|
||||
<monochrome android:drawable="@drawable/ic_launcher_monochrome" />
|
||||
</adaptive-icon>
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<background android:drawable="@color/md_grey_black"/>
|
||||
<foreground android:drawable="@mipmap/ic_launcher_foreground"/>
|
||||
<background android:drawable="@color/md_grey_black" />
|
||||
<foreground android:drawable="@mipmap/ic_launcher_foreground" />
|
||||
<monochrome android:drawable="@drawable/ic_launcher_monochrome" />
|
||||
</adaptive-icon>
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<background android:drawable="@color/md_indigo_700"/>
|
||||
<foreground android:drawable="@mipmap/ic_launcher_foreground"/>
|
||||
<background android:drawable="@color/md_indigo_700" />
|
||||
<foreground android:drawable="@mipmap/ic_launcher_foreground" />
|
||||
<monochrome android:drawable="@drawable/ic_launcher_monochrome" />
|
||||
</adaptive-icon>
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<background android:drawable="@color/md_light_blue_700"/>
|
||||
<foreground android:drawable="@mipmap/ic_launcher_foreground"/>
|
||||
<background android:drawable="@color/md_light_blue_700" />
|
||||
<foreground android:drawable="@mipmap/ic_launcher_foreground" />
|
||||
<monochrome android:drawable="@drawable/ic_launcher_monochrome" />
|
||||
</adaptive-icon>
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<background android:drawable="@color/md_light_green_700"/>
|
||||
<foreground android:drawable="@mipmap/ic_launcher_foreground"/>
|
||||
<background android:drawable="@color/md_light_green_700" />
|
||||
<foreground android:drawable="@mipmap/ic_launcher_foreground" />
|
||||
<monochrome android:drawable="@drawable/ic_launcher_monochrome" />
|
||||
</adaptive-icon>
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<background android:drawable="@color/md_lime_700"/>
|
||||
<foreground android:drawable="@mipmap/ic_launcher_foreground"/>
|
||||
<background android:drawable="@color/md_lime_700" />
|
||||
<foreground android:drawable="@mipmap/ic_launcher_foreground" />
|
||||
<monochrome android:drawable="@drawable/ic_launcher_monochrome" />
|
||||
</adaptive-icon>
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<background android:drawable="@color/md_pink_700"/>
|
||||
<foreground android:drawable="@mipmap/ic_launcher_foreground"/>
|
||||
<background android:drawable="@color/md_pink_700" />
|
||||
<foreground android:drawable="@mipmap/ic_launcher_foreground" />
|
||||
<monochrome android:drawable="@drawable/ic_launcher_monochrome" />
|
||||
</adaptive-icon>
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<background android:drawable="@color/md_purple_700"/>
|
||||
<foreground android:drawable="@mipmap/ic_launcher_foreground"/>
|
||||
<background android:drawable="@color/md_purple_700" />
|
||||
<foreground android:drawable="@mipmap/ic_launcher_foreground" />
|
||||
<monochrome android:drawable="@drawable/ic_launcher_monochrome" />
|
||||
</adaptive-icon>
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<background android:drawable="@color/md_red_700"/>
|
||||
<foreground android:drawable="@mipmap/ic_launcher_foreground"/>
|
||||
<background android:drawable="@color/md_red_700" />
|
||||
<foreground android:drawable="@mipmap/ic_launcher_foreground" />
|
||||
<monochrome android:drawable="@drawable/ic_launcher_monochrome" />
|
||||
</adaptive-icon>
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<background android:drawable="@color/md_teal_700"/>
|
||||
<foreground android:drawable="@mipmap/ic_launcher_foreground"/>
|
||||
<background android:drawable="@color/md_teal_700" />
|
||||
<foreground android:drawable="@mipmap/ic_launcher_foreground" />
|
||||
<monochrome android:drawable="@drawable/ic_launcher_monochrome" />
|
||||
</adaptive-icon>
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<background android:drawable="@color/md_yellow_700"/>
|
||||
<foreground android:drawable="@mipmap/ic_launcher_foreground"/>
|
||||
<background android:drawable="@color/md_yellow_700" />
|
||||
<foreground android:drawable="@mipmap/ic_launcher_foreground" />
|
||||
<monochrome android:drawable="@drawable/ic_launcher_monochrome" />
|
||||
</adaptive-icon>
|
||||
|
|
|
@ -2,16 +2,17 @@
|
|||
<resources>
|
||||
<string name="app_name">Simple Flashlight</string>
|
||||
<string name="app_launcher_name">Flashlight</string>
|
||||
<string name="camera_error">Obtaining the camera failed</string>
|
||||
<string name="camera_permission">Camera permission is necessary for proper stroboscope effect</string>
|
||||
<string name="bright_display">Bright display</string>
|
||||
<string name="camera_error">فشل الحصول على الكاميرا</string>
|
||||
<string name="camera_permission">الحصول على إذن تصوير ضروري للتأثيرات</string>
|
||||
<string name="bright_display">شاشة ساطعة</string>
|
||||
<!-- Settings -->
|
||||
<string name="show_bright_display">Show a bright display button</string>
|
||||
<string name="show_stroboscope">Show a stroboscope button</string>
|
||||
<string name="show_sos">Show an SOS button</string>
|
||||
<string name="turn_flashlight_on">Turn flashlight on at startup</string>
|
||||
<string name="show_bright_display">إظهار زر عرض ساطع</string>
|
||||
<string name="show_stroboscope">إظهار زر ستروبوسكوب</string>
|
||||
<string name="stroboscope">Stroboscope</string>
|
||||
<string name="show_sos">إظهار زر SOS</string>
|
||||
<string name="turn_flashlight_on">قم بتشغيل المصباح عند بدء التشغيل</string>
|
||||
<!--
|
||||
Haven't found some strings? There's more at
|
||||
https://github.com/SimpleMobileTools/Simple-Commons/tree/master/commons/src/main/res
|
||||
-->
|
||||
</resources>
|
||||
</resources>
|
||||
|
|
|
@ -8,10 +8,11 @@
|
|||
<!-- Settings -->
|
||||
<string name="show_bright_display">İşıqlı ekran düyməsi göstər</string>
|
||||
<string name="show_stroboscope">Stroboskop düyməsi göstər</string>
|
||||
<string name="stroboscope">Stroboscope</string>
|
||||
<string name="show_sos">Show an SOS button</string>
|
||||
<string name="turn_flashlight_on">Başlanğıcda fənəri aç</string>
|
||||
<!--
|
||||
Haven't found some strings? There's more at
|
||||
https://github.com/SimpleMobileTools/Simple-Commons/tree/master/commons/src/main/res
|
||||
-->
|
||||
</resources>
|
||||
</resources>
|
||||
|
|
|
@ -2,16 +2,17 @@
|
|||
<resources>
|
||||
<string name="app_name">Simple Flashlight</string>
|
||||
<string name="app_launcher_name">Ліхтарык</string>
|
||||
<string name="camera_error">Obtaining the camera failed</string>
|
||||
<string name="camera_error">Не атрымалася атрымаць камеру</string>
|
||||
<string name="camera_permission">Дазвол на доступ да камеры неабходны для стварэння эфекту страбаскопа</string>
|
||||
<string name="bright_display">Яркі экран</string>
|
||||
<!-- Settings -->
|
||||
<string name="show_bright_display">Паказваць кнопку яркага экрана</string>
|
||||
<string name="show_stroboscope">Паказваць кнопку страбаскопа</string>
|
||||
<string name="stroboscope">Stroboscope</string>
|
||||
<string name="show_sos">Паказваць кнопку СОС</string>
|
||||
<string name="turn_flashlight_on">Уключаць ліхтарык пры запуску</string>
|
||||
<!--
|
||||
Haven't found some strings? There's more at
|
||||
https://github.com/SimpleMobileTools/Simple-Commons/tree/master/commons/src/main/res
|
||||
-->
|
||||
</resources>
|
||||
</resources>
|
||||
|
|
|
@ -3,15 +3,16 @@
|
|||
<string name="app_name">Обикновен фенер</string>
|
||||
<string name="app_launcher_name">Фенер</string>
|
||||
<string name="camera_error">Неуспешен достъп до камера</string>
|
||||
<string name="camera_permission">Camera permission is necessary for proper stroboscope effect</string>
|
||||
<string name="bright_display">Bright display</string>
|
||||
<string name="camera_permission">Разрешение за използване на камерата е необходимо за постигане на подходящ стробоскопичен ефект</string>
|
||||
<string name="bright_display">Ярък дисплей</string>
|
||||
<!-- Settings -->
|
||||
<string name="show_bright_display">Show a bright display button</string>
|
||||
<string name="show_stroboscope">Show a stroboscope button</string>
|
||||
<string name="show_bright_display">Покажи ярък дисплей бутон</string>
|
||||
<string name="show_stroboscope">Покажи стробинг бутон</string>
|
||||
<string name="stroboscope">Stroboscope</string>
|
||||
<string name="show_sos">Показване на SOS бутон</string>
|
||||
<string name="turn_flashlight_on">Включване на фенер при стартиране</string>
|
||||
<!--
|
||||
Haven't found some strings? There's more at
|
||||
https://github.com/SimpleMobileTools/Simple-Commons/tree/master/commons/src/main/res
|
||||
-->
|
||||
</resources>
|
||||
</resources>
|
||||
|
|
|
@ -0,0 +1,18 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<string name="app_name">Jednostavna baterija</string>
|
||||
<string name="app_launcher_name">Baterija</string>
|
||||
<string name="camera_error">Nije moguće pristupiti kameri</string>
|
||||
<string name="camera_permission">Potrebna je dozvola za pristup kameri za pravilan stroboskopski efekt</string>
|
||||
<string name="bright_display">Svijetli ekran</string>
|
||||
<!-- Settings -->
|
||||
<string name="show_bright_display">Prikaži dugme za svijetli ekran</string>
|
||||
<string name="show_stroboscope">Prikaži dugme za stroboskop</string>
|
||||
<string name="stroboscope">Stroboskop</string>
|
||||
<string name="show_sos">Prikaži SOS dugme</string>
|
||||
<string name="turn_flashlight_on">Uključi bateriju pri pokretanju</string>
|
||||
<!--
|
||||
Haven't found some strings? There's more at
|
||||
https://github.com/SimpleMobileTools/Simple-Commons/tree/master/commons/src/main/res
|
||||
-->
|
||||
</resources>
|
|
@ -8,10 +8,11 @@
|
|||
<!-- Settings -->
|
||||
<string name="show_bright_display">Mostra un botó de pantalla lluminosa</string>
|
||||
<string name="show_stroboscope">Mostra un botó d\'estroboscopi</string>
|
||||
<string name="stroboscope">Stroboscope</string>
|
||||
<string name="show_sos">Mostra un botó de SOS</string>
|
||||
<string name="turn_flashlight_on">Activa la llanterna a l\'inici</string>
|
||||
<!--
|
||||
Haven't found some strings? There's more at
|
||||
https://github.com/SimpleMobileTools/Simple-Commons/tree/master/commons/src/main/res
|
||||
-->
|
||||
</resources>
|
||||
</resources>
|
||||
|
|
|
@ -8,10 +8,11 @@
|
|||
<!-- Settings -->
|
||||
<string name="show_bright_display">Zobrazit tlačítko pro jasný displej</string>
|
||||
<string name="show_stroboscope">Zobrazit tlačítko pro stroboskop</string>
|
||||
<string name="stroboscope">Stroboscope</string>
|
||||
<string name="show_sos">Zobrazit tlačítko SOS</string>
|
||||
<string name="turn_flashlight_on">Zapnout svítilnu po spuštění</string>
|
||||
<!--
|
||||
Haven't found some strings? There's more at
|
||||
https://github.com/SimpleMobileTools/Simple-Commons/tree/master/commons/src/main/res
|
||||
-->
|
||||
</resources>
|
||||
</resources>
|
||||
|
|
|
@ -8,10 +8,11 @@
|
|||
<!-- Settings -->
|
||||
<string name="show_bright_display">Dangos botwm dangosydd llachar</string>
|
||||
<string name="show_stroboscope">Dangos botwm strobosgop</string>
|
||||
<string name="stroboscope">Stroboscope</string>
|
||||
<string name="show_sos">Show an SOS button</string>
|
||||
<string name="turn_flashlight_on">Troi\'r fflacholau ymlaen wrth ddechrau</string>
|
||||
<!--
|
||||
Haven't found some strings? There's more at
|
||||
https://github.com/SimpleMobileTools/Simple-Commons/tree/master/commons/src/main/res
|
||||
-->
|
||||
</resources>
|
||||
</resources>
|
||||
|
|
|
@ -8,10 +8,11 @@
|
|||
<!-- Settings -->
|
||||
<string name="show_bright_display">Vis en lys skærmknap</string>
|
||||
<string name="show_stroboscope">Vis en stroboskop-knap</string>
|
||||
<string name="stroboscope">Stroboscope</string>
|
||||
<string name="show_sos">Vis en SOS-knap</string>
|
||||
<string name="turn_flashlight_on">Slå lommelygte til ved start</string>
|
||||
<!--
|
||||
Haven't found some strings? There's more at
|
||||
https://github.com/SimpleMobileTools/Simple-Commons/tree/master/commons/src/main/res
|
||||
-->
|
||||
</resources>
|
||||
</resources>
|
||||
|
|
|
@ -3,15 +3,16 @@
|
|||
<string name="app_name">Schlichte Taschenlampe</string>
|
||||
<string name="app_launcher_name">Taschenlampe</string>
|
||||
<string name="camera_error">Beanspruchen der Kamera fehlgeschlagen</string>
|
||||
<string name="camera_permission">Kamera-Berechtigung ist für den Stroboskopeffekt erforderlich</string>
|
||||
<string name="camera_permission">Kameraberechtigung ist für den Stroboskopeffekt erforderlich</string>
|
||||
<string name="bright_display">Heller Bildschirm</string>
|
||||
<!-- Settings -->
|
||||
<string name="show_bright_display">Schaltfläche für hellen Bildschirm zeigen</string>
|
||||
<string name="show_stroboscope">Schaltfläche für Stroboskop zeigen</string>
|
||||
<string name="stroboscope">Stroboscope</string>
|
||||
<string name="show_sos">Eine SOS-Schaltfläche zeigen</string>
|
||||
<string name="turn_flashlight_on">Taschenlampe beim Start einschalten</string>
|
||||
<!--
|
||||
Haven't found some strings? There's more at
|
||||
https://github.com/SimpleMobileTools/Simple-Commons/tree/master/commons/src/main/res
|
||||
-->
|
||||
</resources>
|
||||
</resources>
|
||||
|
|
|
@ -8,10 +8,11 @@
|
|||
<!-- Settings -->
|
||||
<string name="show_bright_display">Προβολή κουμπιού φωτεινότητας</string>
|
||||
<string name="show_stroboscope">Προβολή κουμπιού στροβοσκοπίου</string>
|
||||
<string name="stroboscope">Stroboscope</string>
|
||||
<string name="show_sos">Προβολή κουμπιού SOS</string>
|
||||
<string name="turn_flashlight_on">Άνοιγμα του φακού κατά την εκκίνηση</string>
|
||||
<!--
|
||||
Haven't found some strings? There's more at
|
||||
https://github.com/SimpleMobileTools/Simple-Commons/tree/master/commons/src/main/res
|
||||
-->
|
||||
</resources>
|
||||
</resources>
|
||||
|
|
|
@ -8,10 +8,11 @@
|
|||
<!-- Settings -->
|
||||
<string name="show_bright_display">Montri butonon por hela ekrano</string>
|
||||
<string name="show_stroboscope">Show a stroboscope button</string>
|
||||
<string name="stroboscope">Stroboscope</string>
|
||||
<string name="show_sos">Show an SOS button</string>
|
||||
<string name="turn_flashlight_on">Turn flashlight on at startup</string>
|
||||
<!--
|
||||
Haven't found some strings? There's more at
|
||||
https://github.com/SimpleMobileTools/Simple-Commons/tree/master/commons/src/main/res
|
||||
-->
|
||||
</resources>
|
||||
</resources>
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<string name="app_name">Linterna Simple</string>
|
||||
<string name="app_name">Linterna sencilla</string>
|
||||
<string name="app_launcher_name">Linterna</string>
|
||||
<string name="camera_error">Ha fallado el acceso a la cámara</string>
|
||||
<string name="camera_permission">El permiso de acceso a la cámara es necesario para un apropiado efecto estroboscópico</string>
|
||||
|
@ -8,10 +8,11 @@
|
|||
<!-- Settings -->
|
||||
<string name="show_bright_display">Mostrar botón de pantalla brillante</string>
|
||||
<string name="show_stroboscope">Mostrar botón de estroboscopio</string>
|
||||
<string name="show_sos">Mostrar botón de SOS</string>
|
||||
<string name="turn_flashlight_on">Encender la linterna al iniciar</string>
|
||||
<string name="stroboscope">Stroboscope</string>
|
||||
<string name="show_sos">Mostrar un botón de SOS</string>
|
||||
<string name="turn_flashlight_on">Encender la linterna al inicio</string>
|
||||
<!--
|
||||
Haven't found some strings? There's more at
|
||||
https://github.com/SimpleMobileTools/Simple-Commons/tree/master/commons/src/main/res
|
||||
-->
|
||||
</resources>
|
||||
</resources>
|
||||
|
|
|
@ -8,10 +8,11 @@
|
|||
<!-- Settings -->
|
||||
<string name="show_bright_display">Näita nuppu ekraanil kirkana</string>
|
||||
<string name="show_stroboscope">Näita stroboskoobi nuppu</string>
|
||||
<string name="stroboscope">Stroboscope</string>
|
||||
<string name="show_sos">Näita SOS-nuppu</string>
|
||||
<string name="turn_flashlight_on">Rakenduse käivitamisel lülita taskulamp sisse</string>
|
||||
<!--
|
||||
Haven't found some strings? There's more at
|
||||
https://github.com/SimpleMobileTools/Simple-Commons/tree/master/commons/src/main/res
|
||||
-->
|
||||
</resources>
|
||||
</resources>
|
||||
|
|
|
@ -1,17 +1,18 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<string name="app_name">Simple Flashlight</string>
|
||||
<string name="app_launcher_name">Taskulammpu</string>
|
||||
<string name="app_name">Yksinkertainen taskulamppu</string>
|
||||
<string name="app_launcher_name">Taskulamppu</string>
|
||||
<string name="camera_error">Kameran saanti epäonnistui</string>
|
||||
<string name="camera_permission">Lupa kameraan vaaditaan oikean stroboskooppisen vaikutuksen saavuttamiseksi</string>
|
||||
<string name="bright_display">Kirkas näyttö</string>
|
||||
<!-- Settings -->
|
||||
<string name="show_bright_display">Näytä kirkas näyttö -painike</string>
|
||||
<string name="show_stroboscope">Näytä stroboskooppipainike</string>
|
||||
<string name="stroboscope">Stroboscope</string>
|
||||
<string name="show_sos">Näytä SOS-painike</string>
|
||||
<string name="turn_flashlight_on">Kytke taskulamppu päälle käynnistyksen yhteydessä</string>
|
||||
<!--
|
||||
Haven't found some strings? There's more at
|
||||
https://github.com/SimpleMobileTools/Simple-Commons/tree/master/commons/src/main/res
|
||||
-->
|
||||
</resources>
|
||||
</resources>
|
||||
|
|
|
@ -2,16 +2,17 @@
|
|||
<resources>
|
||||
<string name="app_name">Lampe de poche simple</string>
|
||||
<string name="app_launcher_name">Lampe de poche</string>
|
||||
<string name="camera_error">Échec de l\'obtention de l\'appareil photo</string>
|
||||
<string name="camera_permission">L\'autorisation d\'accès à l\'appareil photo est nécessaire pour un effet stroboscope correct</string>
|
||||
<string name="camera_error">Échec de l\'obtention de l\'objectif photo-vidéo</string>
|
||||
<string name="camera_permission">L\'autorisation d\'accès à l\'appareil photo est nécessaire pour un effet stroboscopique correct</string>
|
||||
<string name="bright_display">Affichage lumineux</string>
|
||||
<!-- Settings -->
|
||||
<string name="show_bright_display">Afficher un bouton écran lumineux</string>
|
||||
<string name="show_bright_display">Afficher un bouton d\'affichage lumineux</string>
|
||||
<string name="show_stroboscope">Afficher un bouton stroboscope</string>
|
||||
<string name="show_sos">Afficher un bouton SOS</string>
|
||||
<string name="turn_flashlight_on">Activer la lampe de poche au démarrage</string>
|
||||
<string name="stroboscope">Stroboscope</string>
|
||||
<string name="show_sos">Afficher un bouton « S.O.S. »</string>
|
||||
<string name="turn_flashlight_on">Allumer la lampe de poche au démarrage</string>
|
||||
<!--
|
||||
Haven't found some strings? There's more at
|
||||
https://github.com/SimpleMobileTools/Simple-Commons/tree/master/commons/src/main/res
|
||||
-->
|
||||
</resources>
|
||||
</resources>
|
||||
|
|
|
@ -4,14 +4,15 @@
|
|||
<string name="app_launcher_name">Lanterna</string>
|
||||
<string name="camera_error">Erro ao obter a cámara</string>
|
||||
<string name="camera_permission">O permiso da cámara é necesario para utilizar o efecto estroboscopio</string>
|
||||
<string name="bright_display">Pantalal brillante</string>
|
||||
<string name="bright_display">Pantalla brillante</string>
|
||||
<!-- Settings -->
|
||||
<string name="show_bright_display">Mostrar botón para iluminar a pantalla</string>
|
||||
<string name="show_stroboscope">Mostrar botón de estroboscopio</string>
|
||||
<string name="show_bright_display">Mostrar un botón para iluminala pantalla</string>
|
||||
<string name="show_stroboscope">Mostrar un botón estroboscopio</string>
|
||||
<string name="stroboscope">Stroboscope</string>
|
||||
<string name="show_sos">Mostrar un botón de SOS</string>
|
||||
<string name="turn_flashlight_on">Activar lanterna ao iniciar</string>
|
||||
<string name="turn_flashlight_on">Acendela lanterna ao iniciar</string>
|
||||
<!--
|
||||
Haven't found some strings? There's more at
|
||||
https://github.com/SimpleMobileTools/Simple-Commons/tree/master/commons/src/main/res
|
||||
-->
|
||||
</resources>
|
||||
</resources>
|
||||
|
|
|
@ -8,10 +8,11 @@
|
|||
<!-- Settings -->
|
||||
<string name="show_bright_display">Prikaži gumb za svijetli ekran</string>
|
||||
<string name="show_stroboscope">Prikaži gumb za stroboskop</string>
|
||||
<string name="stroboscope">Stroboskop</string>
|
||||
<string name="show_sos">Prikaži SOS gumb</string>
|
||||
<string name="turn_flashlight_on">Uključi svjetiljku pri pokretanju</string>
|
||||
<!--
|
||||
Haven't found some strings? There's more at
|
||||
https://github.com/SimpleMobileTools/Simple-Commons/tree/master/commons/src/main/res
|
||||
-->
|
||||
</resources>
|
||||
</resources>
|
||||
|
|
|
@ -8,10 +8,11 @@
|
|||
<!-- Settings -->
|
||||
<string name="show_bright_display">Fényes kijelző gomb megjelenítése</string>
|
||||
<string name="show_stroboscope">Stroboszkóp gomb megjelenítése</string>
|
||||
<string name="stroboscope">Stroboscope</string>
|
||||
<string name="show_sos">SOS gomb megjelenítése</string>
|
||||
<string name="turn_flashlight_on">Zseblámpa bekapcsolása indításkor</string>
|
||||
<!--
|
||||
Haven't found some strings? There's more at
|
||||
https://github.com/SimpleMobileTools/Simple-Commons/tree/master/commons/src/main/res
|
||||
-->
|
||||
</resources>
|
||||
</resources>
|
||||
|
|
|
@ -8,10 +8,11 @@
|
|||
<!-- Settings -->
|
||||
<string name="show_bright_display">Tampilkan tombol tampilan cerah</string>
|
||||
<string name="show_stroboscope">Tampilkan tombol stroboscope</string>
|
||||
<string name="stroboscope">Stroboscope</string>
|
||||
<string name="show_sos">Tampilkan tombol SOS</string>
|
||||
<string name="turn_flashlight_on">Nyalakan senter saat memulai</string>
|
||||
<!--
|
||||
Haven't found some strings? There's more at
|
||||
https://github.com/SimpleMobileTools/Simple-Commons/tree/master/commons/src/main/res
|
||||
-->
|
||||
</resources>
|
||||
</resources>
|
||||
|
|
|
@ -0,0 +1,14 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<string name="app_name">Simple Flashlight</string>
|
||||
<string name="app_launcher_name">Flashlight</string>
|
||||
<string name="camera_error">Obtaining the camera failed</string>
|
||||
<string name="camera_permission">Camera permission is necessary for proper stroboscope effect</string>
|
||||
<string name="bright_display">Bright display</string>
|
||||
<!-- Settings -->
|
||||
<string name="show_bright_display">Show a bright display button</string>
|
||||
<string name="show_stroboscope">Show a stroboscope button</string>
|
||||
<string name="stroboscope">Stroboscope</string>
|
||||
<string name="show_sos">Show an SOS button</string>
|
||||
<string name="turn_flashlight_on">Turn flashlight on at startup</string>
|
||||
</resources>
|
|
@ -1,6 +1,6 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<string name="app_name">Semplice torcia</string>
|
||||
<string name="app_name">Torcia Semplice</string>
|
||||
<string name="app_launcher_name">Torcia</string>
|
||||
<string name="camera_error">Impossibile rilevare la fotocamera</string>
|
||||
<string name="camera_permission">Il permesso per la fotocamera è necessario per l\'effetto stroboscopico</string>
|
||||
|
@ -8,10 +8,11 @@
|
|||
<!-- Settings -->
|
||||
<string name="show_bright_display">Mostra un pulsante per lo schermo luminoso</string>
|
||||
<string name="show_stroboscope">Mostra un pulsante per l\'effetto stroboscopico</string>
|
||||
<string name="stroboscope">Stroboscope</string>
|
||||
<string name="show_sos">Mostra un pulsante SOS</string>
|
||||
<string name="turn_flashlight_on">Accendi la torcia all\'avvio</string>
|
||||
<!--
|
||||
Haven't found some strings? There's more at
|
||||
https://github.com/SimpleMobileTools/Simple-Commons/tree/master/commons/src/main/res
|
||||
-->
|
||||
</resources>
|
||||
</resources>
|
||||
|
|
|
@ -8,10 +8,11 @@
|
|||
<!-- Settings -->
|
||||
<string name="show_bright_display">הצג כפתור תצוגה בהיר</string>
|
||||
<string name="show_stroboscope">הצג כפתור סטרובוסקופ</string>
|
||||
<string name="stroboscope">Stroboscope</string>
|
||||
<string name="show_sos">הצג כפתור SOS</string>
|
||||
<string name="turn_flashlight_on">הדלק את הפנס בעת ההפעלה</string>
|
||||
<!--
|
||||
Haven't found some strings? There's more at
|
||||
https://github.com/SimpleMobileTools/Simple-Commons/tree/master/commons/src/main/res
|
||||
-->
|
||||
</resources>
|
||||
</resources>
|
||||
|
|
|
@ -8,10 +8,11 @@
|
|||
<!-- Settings -->
|
||||
<string name="show_bright_display">明るく表示ボタンを表示</string>
|
||||
<string name="show_stroboscope">ストロボボタンを表示</string>
|
||||
<string name="stroboscope">Stroboscope</string>
|
||||
<string name="show_sos">SOSボタンを表示</string>
|
||||
<string name="turn_flashlight_on">起動時にフラッシュライトを点灯</string>
|
||||
<!--
|
||||
Haven't found some strings? There's more at
|
||||
https://github.com/SimpleMobileTools/Simple-Commons/tree/master/commons/src/main/res
|
||||
-->
|
||||
</resources>
|
||||
</resources>
|
||||
|
|
|
@ -8,10 +8,11 @@
|
|||
<!-- Settings -->
|
||||
<string name="show_bright_display">브라이트 디스플레이 버튼 활성화</string>
|
||||
<string name="show_stroboscope">스트로보 스코프 버튼 활성화</string>
|
||||
<string name="stroboscope">Stroboscope</string>
|
||||
<string name="show_sos">Show an SOS button</string>
|
||||
<string name="turn_flashlight_on">Turn flashlight on at startup</string>
|
||||
<!--
|
||||
Haven't found some strings? There's more at
|
||||
https://github.com/SimpleMobileTools/Simple-Commons/tree/master/commons/src/main/res
|
||||
-->
|
||||
</resources>
|
||||
</resources>
|
||||
|
|