Compare commits

...

309 Commits

Author SHA1 Message Date
Tibor Kaputa ddf576aa04
Merge pull request #215 from weblate/weblate-simple-mobile-tools-simple-flashlight
Translations update from Hosted Weblate
2023-10-18 15:21:11 +02:00
Agnieszka C 84279de811
Translated using Weblate (Polish)
Currently translated at 100.0% (10 of 10 strings)

Translation: Simple Mobile Tools/Simple Flashlight
Translate-URL: https://hosted.weblate.org/projects/simple-mobile-tools/simple-flashlight/pl/
2023-10-18 13:08:18 +00:00
tibbi ac6513332b updating changelog 2023-10-18 15:07:49 +02:00
tibbi f5ab9462fd update version to 5.10.1 2023-10-18 15:07:43 +02:00
tibbi 9689d4f6fc updating commons 2023-10-18 14:59:55 +02:00
Tibor Kaputa 7f739c8b62
Merge pull request #213 from esensar/compose-migration
Migrate application to compose
2023-10-18 14:29:22 +02:00
Ensar Sarajčić 9fea2bca1a Add background for status and navigation bar in widget configuration activities 2023-10-18 13:29:28 +02:00
Ensar Sarajčić 18c8bf3c7a Fix error state for stroboscope and SOS 2023-10-17 13:03:08 +02:00
Ensar Sarajčić b0ea8d8ef2 Fix flashlight button state on errors 2023-10-17 12:59:41 +02:00
Ensar Sarajčić 27c3aa60d0 Add extra padding to sliders section to prevent overlap with timer 2023-10-17 10:58:15 +02:00
Ensar Sarajčić d36afb3e13 Add background to sleep timer element 2023-10-17 08:25:51 +02:00
Ensar Sarajčić b3b0bc84f9 Clean up `SleepTimerCustomAlertDialog` 2023-10-17 08:24:05 +02:00
Ensar Sarajčić b57e782613 Prevent drawing behind system bars in `WidgetConfigureScreen` 2023-10-17 08:04:21 +02:00
Ensar Sarajčić 13a794fe12 Merge branch 'master' into compose-migration 2023-10-16 11:34:39 +02:00
Ensar Sarajčić c755c67011 Update commons to remove the need for `minActiveState` 2023-10-16 11:03:42 +02:00
Ensar Sarajčić afe23bfb2e Use new compat helpers for window flags 2023-10-16 09:54:04 +02:00
Tibor Kaputa 899d616eb3
Merge pull request #214 from weblate/weblate-simple-mobile-tools-simple-flashlight
Translations update from Hosted Weblate
2023-10-14 21:26:05 +02:00
Ensar Sarajčić c546aab7f1 Remove needless call for insets controller in `BrightDisplayActivity` 2023-10-13 11:35:14 +02:00
Ensar Sarajčić cef9f6e62b Remove `getCameraPermissionLauncher` 2023-10-13 11:34:50 +02:00
Ensar Sarajčić f21cd4ff49 Remove needless ArrayLists and `Arrays.toList` calls 2023-10-13 11:33:02 +02:00
Ensar Sarajčić 7533ad1fa2 Use `buildList` in `secondsToString` in `MainActivity` 2023-10-13 11:29:30 +02:00
Ensar Sarajčić 1600a072ef Use more descriptive names for `showSleepTimerPermission` arguments 2023-10-13 11:27:53 +02:00
Ensar Sarajčić e190cac2a3 Inline `handlePermissionResult` 2023-10-13 11:24:53 +02:00
Ensar Sarajčić dabdfdcd7d Replace `else if` with `when` in `MainActivity` 2023-10-13 11:23:10 +02:00
Ensar Sarajčić f25601db6b Move radio item list building for SleepTimer into a separate function 2023-10-13 11:20:43 +02:00
Ensar Sarajčić 4b7c4350d4 Move colors to parameters of dialog state functions 2023-10-13 11:15:15 +02:00
Ensar Sarajčić d9d3928705 Prevent updating flashlight button state before turning updating flashlight 2023-10-13 11:08:31 +02:00
Ensar Sarajčić 03b0fbb836 Update commons for menu colors fix 2023-10-12 09:33:25 +02:00
Lionel HANNEQUIN 631d0731c7
Translated using Weblate (French)
Currently translated at 100.0% (9 of 9 strings)

Translation: Simple Mobile Tools/Simple Flashlight
Translate-URL: https://hosted.weblate.org/projects/simple-mobile-tools/simple-flashlight/fr/
2023-10-11 14:05:18 +02:00
Ensar Sarajčić 4b65350e24 Update commons 2023-10-10 09:23:16 +02:00
Puppelimies b37b39e43d
Translated using Weblate (Swedish)
Currently translated at 100.0% (9 of 9 strings)

Translation: Simple Mobile Tools/Simple Flashlight
Translate-URL: https://hosted.weblate.org/projects/simple-mobile-tools/simple-flashlight/sv/
2023-10-10 09:17:02 +02:00
Ensar Sarajčić 88792ccb8d Remove `preferenceValueColor` override in `SettingsScreen` 2023-10-09 16:48:39 +02:00
Ensar Sarajčić efd6c71c63 Update simple-commons 2023-10-09 16:26:13 +02:00
Ensar Sarajčić 30c95833c3 Add `useEnglish` to `SettingsScreen` 2023-10-09 13:18:25 +02:00
Ensar Sarajčić 410f2759fc Leave `android.nonTransitiveRClass` at default value 2023-10-09 12:04:41 +02:00
Ensar Sarajčić d2473cfb1f Use named parameter for `cancelCallback` in `CheckFeatureLocked` 2023-10-09 09:41:19 +02:00
Ensar Sarajčić d40d5329e5 Add navigation bar padding to `SleepTimer` on `MainScreen` 2023-10-09 09:16:01 +02:00
Ensar Sarajčić 9d46496807 Replace `getMultiplier` with `UnitItem` and stored multiplier value 2023-10-09 09:14:31 +02:00
Ensar Sarajčić 2404943fe2 Use `SettingsHorizontalDivider` instead of `HorizontalDivider` 2023-10-09 08:29:22 +02:00
Ensar Sarajčić 3579f61cb9 Simplify padding for slider in `MainScreen` 2023-10-09 08:28:46 +02:00
Ensar Sarajčić b1b4c46dc3 Make `SmallButton` component for `BrightDisplayButton` and `StroboscopeButton` 2023-10-09 08:26:22 +02:00
Ensar Sarajčić c59108e1ad Make `cancel` in `SleepTimer` synchronized too 2023-10-09 08:18:38 +02:00
Ensar Sarajčić 82c4acc96f Make `context` private in `MyCameraImpl` 2023-10-09 08:17:56 +02:00
Ensar Sarajčić b290fd0502 Use `divider_grey` instead of `Color.Gray` for `SleepTimer` 2023-10-09 08:12:05 +02:00
Ensar Sarajčić b5bd119012 Set better defaults for brightness and stroboscope sliders 2023-10-06 12:57:09 +02:00
Ensar Sarajčić d9a7598e59 Fix feature locked dialog in widget configuration 2023-10-06 12:50:25 +02:00
Ensar Sarajčić 539cf694dc Add edge to edge to `MainActivity` 2023-10-06 11:49:06 +02:00
Ensar Sarajčić 270480ead5 Add verticalScroll to `MainScreen` 2023-10-06 11:38:46 +02:00
Ensar Sarajčić 74f4675f19 Extract dialogs and permissions into separate composables 2023-10-06 11:29:20 +02:00
Ensar Sarajčić b536626c3c Use compose version of `appLaunched` 2023-10-06 11:18:27 +02:00
Ensar Sarajčić 9f6ba77f98 Use `when` instead of `else if` in `Activity.kt` 2023-10-06 11:10:24 +02:00
Ensar Sarajčić f2c8b0828d gUpdate compose dependencies 2023-10-06 08:56:46 +02:00
Ensar Sarajčić 29081b032c Use `AppTheme` instead of `AppThemeSurface` for properly transparent widget configuration screens 2023-10-05 16:52:27 +02:00
Ensar Sarajčić 0cfcc9b900 Use compose version of `CheckAppOnSdCard` 2023-10-05 16:50:25 +02:00
Ensar Sarajčić a810c0d3ef Make timer staring synchronized 2023-10-05 14:40:34 +02:00
Ensar Sarajčić c825bf16a2 Clean up color picker creation code 2023-10-05 14:36:20 +02:00
Ensar Sarajčić 2c99bd9c06 Migrate color picker in `WidgetTorchConfigureActivity` to compose 2023-10-05 14:08:43 +02:00
Ensar Sarajčić a1bdd65dbc Migrate color picker in `WidgetBrightDisplayConfigureActivity` to compose 2023-10-05 14:05:56 +02:00
Ensar Sarajčić 3c4c4a4001 Use `eventValue` for `isOrWasThankYouInstalled` 2023-10-05 14:00:21 +02:00
Ensar Sarajčić 6c8b301c9f Migrate `FeatureLockedDialog` in `WidgetTorchConfigureActivity` to compose 2023-10-05 13:59:12 +02:00
Ensar Sarajčić d28b51409b Migrate `FeatureLockedDialog` in `WidgetBrightDisplayConfigureActivity` to compose 2023-10-05 13:49:52 +02:00
Ensar Sarajčić 6893454559 Use method references in WidgetBrightDisplayConfigureActivity 2023-10-05 13:34:37 +02:00
Ensar Sarajčić 8ea675a743 Use method references in `WidgetTorchConfigureActivity` 2023-10-05 13:34:15 +02:00
Ensar Sarajčić 6372066b8e Remove unnecessary fake check when launching CustomizationActivity 2023-10-05 13:22:37 +02:00
Ensar Sarajčić 28ab74caa1 Replace `MaterialTheme` references with `SimpleTheme` 2023-10-05 13:19:31 +02:00
Ensar Sarajčić af6691c06a Remember items for custom sleep timer dialog 2023-10-05 13:16:44 +02:00
Ensar Sarajčić c33664b9e7 Show custom sleep timer dialog via callback 2023-10-05 13:10:18 +02:00
Ensar Sarajčić 21a6196896 Move `AlertDialogState` to parameters of `ColorPicker` 2023-10-05 13:08:25 +02:00
Ensar Sarajčić acc8500bd2 Use proper default value for `brightDisplayColor` 2023-10-05 13:07:42 +02:00
Ensar Sarajčić 8a30781893 Use non deprecated flags in BrightDisplayActivity 2023-10-05 13:06:53 +02:00
Ensar Sarajčić 0a37a82ac9 Replace deprecated `getColor` usage 2023-10-05 12:53:28 +02:00
Ensar Sarajčić 7defcd49ff Add `@Immutable` to `AppDimensions` 2023-10-05 12:50:26 +02:00
Ensar Sarajčić 47159f5f54 Use `SimpleTheme.dimens` in `SleepTimerCustomAlertDialog` 2023-10-05 12:50:00 +02:00
Ensar Sarajčić b5b215af6e Make `onCancelClick` nullable 2023-10-05 12:47:05 +02:00
Ensar Sarajčić 15dcb65fbc Pu `SleepTimerCustomAlertDialog` items in `remember` 2023-10-05 12:46:01 +02:00
Ensar Sarajčić 17ac263c5d Use `DialogSurface` for `SleepTimerCustomAlertDialog` 2023-10-05 12:44:38 +02:00
Ensar Sarajčić 057cfefb64 Use `stateIn` to move default values to viewModel 2023-10-05 12:39:40 +02:00
Ensar Sarajčić 34ac99fb63 Clean up `BrightDisplayActivity` method references 2023-10-05 12:29:37 +02:00
Ensar Sarajčić 59537d28bd Migrate color picker to compose 2023-10-05 10:34:06 +02:00
Ensar Sarajčić c354d115ee Fix `MyCameraImpl` crash 2023-10-05 09:43:50 +02:00
Ensar Sarajčić eae63898e3 Use compose `PermissionRequiredAlertDialog` for sleep timer permission 2023-10-05 09:43:37 +02:00
Tibor Kaputa 680b313372
updating the f-droid icon 2023-10-05 09:16:21 +02:00
Ensar Sarajčić c37ced08a7 Migrate SleepTimerCustomDialog to compose 2023-10-05 08:40:31 +02:00
Ensar Sarajčić a3e188529d Update commons to update RadioGroupAlertDialog 2023-10-04 17:41:36 +02:00
Ensar Sarajčić 6296d893b0 Use `apply` when building `SleepTimerRadioDialog` 2023-10-04 16:36:47 +02:00
Ensar Sarajčić 2fd3dc5c77 Use compose RadioGroupDialog 2023-10-04 16:24:06 +02:00
Ensar Sarajčić 9e3b207509 Split `SettingsScreen` into sections 2023-10-03 13:27:41 +02:00
Ensar Sarajčić 2f6000db6a Add accessibility string for stroboscope 2023-10-03 13:19:42 +02:00
Ensar Sarajčić 50820bd948 Update Android gradle plugin to 8.1.2 2023-10-03 13:14:17 +02:00
Ensar Sarajčić 17946431ba Add annotations for `Int` values in WidgetConfigureScreen for clarity 2023-10-03 13:13:59 +02:00
Ensar Sarajčić 3323b2fb70 Remove usages of `dimensionResource` 2023-10-03 13:06:50 +02:00
Ensar Sarajčić 3f901ff290 Split compose screens into multiple smaller sections 2023-10-03 09:10:32 +02:00
Ensar Sarajčić c644def18e Move action building to a separate function 2023-10-03 08:08:39 +02:00
Ensar Sarajčić ee9a539cf5 Remove EventBus usage 2023-10-02 18:24:02 +02:00
Ensar Sarajčić 163e053e1d Remove unnecessary modifiers from SleepTimer 2023-10-02 17:15:58 +02:00
Ensar Sarajčić e111bce5f2 Remove ConstraintLayout from compose 2023-10-02 17:08:28 +02:00
Ensar Sarajčić 0767d76345 Move "SOS" to strings 2023-10-02 17:00:17 +02:00
Ensar Sarajčić 50f0be9e20 Use `rememberMutableInteractionSource` 2023-10-02 16:59:32 +02:00
Ensar Sarajčić 3a17008fe9 Remove unnecessary elvis operator from BrightDisplayScreen 2023-10-02 16:54:39 +02:00
Ensar Sarajčić 62484fd3c7 Migrate SettingsScreen to new commons naming 2023-10-02 16:53:48 +02:00
Ensar Sarajčić 2e1821320f Use derived state for contrastColor in BrightDisplayActivity 2023-10-02 16:53:39 +02:00
Ensar Sarajčić 10fa019813 Use `asFlowNonNull` for all flow properties in `Config` 2023-10-02 16:44:15 +02:00
Ensar Sarajčić 132b469b44 Change base for all activities to `ComponentActivity` 2023-10-02 16:41:59 +02:00
Ensar Sarajčić 81096e35a6 Properly reflect flash state in main screen icons 2023-10-02 12:59:57 +02:00
Ensar Sarajčić 3414295887 Fix stroboscope stored progress 2023-10-02 12:45:38 +02:00
Ensar Sarajčić 87e92df993 Fix SleepTimer visibility on main screen 2023-10-02 12:37:33 +02:00
Ensar Sarajčić cd02f52d12 Fix light theme colors 2023-10-02 10:42:18 +02:00
Ensar Sarajčić de2ce0ea73 Properly handle changing preferences values for main screen 2023-10-02 09:49:00 +02:00
Ensar Sarajčić b61288407b Remove ripple effect from main buttons 2023-10-02 09:20:20 +02:00
Ensar Sarajčić 7937a71b0d Migrate MainActivity to compose 2023-10-02 09:06:39 +02:00
Tibor Kaputa b505f7d3ce
Merge pull request #212 from weblate/weblate-simple-mobile-tools-simple-flashlight
Translations update from Hosted Weblate
2023-09-28 23:10:09 +02:00
Ensar Sarajčić 4c5deb10e4 Migrate WidgetTorchConfigureActivity to compose 2023-09-28 17:24:53 +02:00
Ensar Sarajčić 2a5011fb22 Use dimens for SleepTimer instead of hardcoded dp values 2023-09-28 16:59:20 +02:00
Ensar Sarajčić 0ff554a835 Migrate WidgetBrightDisplayConfigureActivity to compose 2023-09-28 16:57:00 +02:00
Ensar Sarajčić 68f4e32ce2 Migrate BrightDisplayActivity to compose 2023-09-28 15:09:52 +02:00
Ensar Sarajčić ee7780f9e7 Use `asFlow` from BaseConfig 2023-09-28 13:17:17 +02:00
Ensar Sarajčić 1e1dacf7be Migrate SettingsActivity to compose 2023-09-28 12:24:18 +02:00
Lionel HANNEQUIN ac8fc71534
Translated using Weblate (French)
Currently translated at 100.0% (9 of 9 strings)

Translation: Simple Mobile Tools/Simple Flashlight
Translate-URL: https://hosted.weblate.org/projects/simple-mobile-tools/simple-flashlight/fr/
2023-09-28 05:56:58 +02:00
gallegonovato f5a4faa576
Translated using Weblate (Spanish)
Currently translated at 100.0% (10 of 10 strings)

Translation: Simple Mobile Tools/Simple Flashlight metadata
Translate-URL: https://hosted.weblate.org/projects/simple-mobile-tools/simple-flashlight-metadata/es/
2023-09-27 13:02:17 +00:00
Puppelimies 8bb7b83e39
Translated using Weblate (Swedish)
Currently translated at 100.0% (10 of 10 strings)

Translation: Simple Mobile Tools/Simple Flashlight metadata
Translate-URL: https://hosted.weblate.org/projects/simple-mobile-tools/simple-flashlight-metadata/sv/
2023-09-25 07:01:36 +02:00
Tibor Kaputa 6c3c5f0323
Merge pull request #211 from weblate/weblate-simple-mobile-tools-simple-flashlight
Translations update from Hosted Weblate
2023-09-23 19:09:48 +02:00
gallegonovato eda4fdfd40
Translated using Weblate (Spanish)
Currently translated at 100.0% (10 of 10 strings)

Translation: Simple Mobile Tools/Simple Flashlight metadata
Translate-URL: https://hosted.weblate.org/projects/simple-mobile-tools/simple-flashlight-metadata/es/
2023-09-23 17:02:04 +02:00
gallegonovato 369050728a
Translated using Weblate (Spanish)
Currently translated at 100.0% (10 of 10 strings)

Translation: Simple Mobile Tools/Simple Flashlight metadata
Translate-URL: https://hosted.weblate.org/projects/simple-mobile-tools/simple-flashlight-metadata/es/
2023-09-22 09:23:49 +02:00
Lionel HANNEQUIN efbb7804db
Translated using Weblate (French)
Currently translated at 100.0% (10 of 10 strings)

Translation: Simple Mobile Tools/Simple Flashlight metadata
Translate-URL: https://hosted.weblate.org/projects/simple-mobile-tools/simple-flashlight-metadata/fr/
2023-09-21 04:03:49 +02:00
Tibor Kaputa ceed63aaa4
Merge pull request #210 from esensar/fix/camera-null-crashes
Prevent null cameraId in CameraFlash
2023-09-20 12:11:55 +02:00
Ensar Sarajčić 97b5389bc6 Wrap null safe calls to `cameraFlash` with toasting 2023-09-20 11:57:47 +02:00
Ensar Sarajčić 0b64092651 Handle cases when `camerFlash` may be null in `MyCameraImpl` 2023-09-20 11:26:03 +02:00
Ensar Sarajčić 2a8d7c2a8c Prevent null cameraId in CameraFlash 2023-09-20 11:11:21 +02:00
Tibor Kaputa 1ce4c6ef65
Merge pull request #209 from esensar/gradle-deprecation-warnings
Clean up gradle deprecation warnings
2023-09-13 14:39:04 +02:00
Ensar Sarajčić 9691b0103c Clean up gradle deprecation warnings 2023-09-13 13:37:10 +02:00
Tibor Kaputa a183c22062
Merge pull request #208 from esensar/version-catalog-migration
Migrate to versions catalog
2023-09-07 12:14:45 +02:00
Ensar Sarajčić c25feb637a Use consistent version ref naming style 2023-09-07 12:09:31 +02:00
Ensar Sarajčić 44ed487c98 Migrate to versions catalog 2023-09-07 11:58:09 +02:00
tibbi aa381a8a52 updating changelog 2023-09-07 11:21:44 +02:00
tibbi cfec55d9eb update version to 5.10.0 2023-09-07 11:21:38 +02:00
tibbi 6142287e45 updating commons 2023-09-07 11:15:50 +02:00
Tibor Kaputa 3924b33ebb
Merge pull request #207 from esensar/feature/105-sleep-timer
Add sleep timer
2023-09-06 22:05:35 +02:00
Tibor Kaputa e73737f2c4
renaming some parameters 2023-09-06 21:55:58 +02:00
Ensar Sarajčić da0b5d341c Offset sleep-timer on BrightDisplayActivity from navigationBar 2023-09-06 10:57:20 +02:00
Ensar Sarajčić 77c8d50cf4 Close app when timer runs out on BrightDisplayActivity 2023-09-06 10:49:22 +02:00
Ensar Sarajčić 174b2ac803 Use more sensible values for sleep timer
This also changes all of these items to use `getQuantityString` instead of
manually appending values.
2023-09-06 10:41:25 +02:00
Ensar Sarajčić c55e784081 Fix 1 minute radio item string 2023-09-06 10:35:34 +02:00
Ensar Sarajčić 788ef6f01f Add radio button for seconds for custom sleep timer 2023-09-06 09:58:24 +02:00
Ensar Sarajčić c00d4cc30c Add more lower default values for sleep timer 2023-09-06 08:10:21 +02:00
Ensar Sarajčić 2572f7cfbf Properly update sleep timer color on resume 2023-09-06 08:08:28 +02:00
Ensar Sarajčić 543362cccb Update Simple-Commons ref 2023-09-06 08:08:18 +02:00
Ensar Sarajčić 482aef3d65 Use shared sleep_timer string 2023-09-04 16:49:34 +02:00
Ensar Sarajčić db5b553ce8 Add sleep timer
This closes #105
2023-09-04 10:39:33 +02:00
Tibor Kaputa 10c3913fed
Merge pull request #206 from fatihergin/feature/migrating-to-sdk-34
Feature/migrating to sdk 34
2023-08-30 14:22:53 +02:00
Tibor Kaputa aec0fb8e9a
updating commons 2023-08-30 14:22:45 +02:00
fatih ergin c58a4aa1f2 make activity inflating consistent across simple apps 2023-08-25 22:49:39 +03:00
fatih ergin 3a40031532 update compile sdk to 34
update kotlin version to 1.9.0
2023-08-25 22:48:48 +03:00
Tibor Kaputa d1d3b698f2
Merge pull request #205 from fatihergin/feature/bind-activities-consistently-across-the-simple-apps
make activity inflating consistent across simple apps
2023-08-16 19:31:23 +02:00
fatih ergin 8f1cbec591 make activity inflating consistent across simple apps 2023-08-16 13:14:07 +03:00
Tibor Kaputa 6747a9a663
Merge pull request #204 from weblate/weblate-simple-mobile-tools-simple-flashlight
Translations update from Hosted Weblate
2023-08-14 17:52:35 +02:00
Tibor Kaputa 956040e5ac
Update full_description.txt 2023-08-14 17:52:26 +02:00
Milan Šalka 2ddab7ac59
Translated using Weblate (Slovak)
Currently translated at 100.0% (9 of 9 strings)

Translation: Simple Mobile Tools/Simple Flashlight metadata
Translate-URL: https://hosted.weblate.org/projects/simple-mobile-tools/simple-flashlight-metadata/sk/
2023-08-11 12:51:42 +02:00
Tibor Kaputa 3af5434fad
Merge pull request #203 from fatihergin/feature/migrating-to-viewbinding
Feature/migrating to viewbinding
2023-08-01 23:37:32 +02:00
fatih ergin bc7e02810e replace kotlin synthetic usages with viewbinding 2023-08-01 22:54:22 +03:00
fatih ergin 3e869f4473 remove deprecated kotlin-android-extensions and enable viewbinding 2023-08-01 22:53:13 +03:00
Tibor Kaputa 7d3c398a4b
Merge pull request #202 from htetoh/patch-1
fixing language code
2023-07-31 18:03:00 +02:00
htetoh fde757eeb5
fixing language code 2023-07-31 22:14:28 +06:30
Tibor Kaputa 92bba84b70
Merge pull request #201 from htetoh/patch-1
Adding Burmese strings
2023-07-31 15:40:06 +02:00
htetoh d50323f977
Adding Burmese strings 2023-07-31 18:46:18 +06:30
tibbi 121fcddf90 updating commons 2023-07-25 15:45:56 +02:00
Tibor Kaputa 6a351fe3c5
Merge pull request #200 from Dejvino/bugfix/159
Fix #159: Button remains in pressed state if you turn screen lock on/off
2023-07-25 15:28:30 +02:00
Dejvino f9a1bb1e04 Fix #159: Button remains in pressed state if you turn screen lock on/off 2023-07-11 06:22:39 +02:00
tibbi be1ba1a8b9 replacing jcenter with mavenCentral 2023-06-23 10:51:49 +02:00
tibbi 67754cd060 updating changelog 2023-05-15 20:55:47 +02:00
tibbi 3d4a1a651b update version to 5.9.2 2023-05-15 20:55:40 +02:00
tibbi b1c2cb84b0 Merge branch 'master' of github.com:SimpleMobileTools/Simple-Flashlight 2023-05-15 20:43:41 +02:00
tibbi 276bbcb7b0 updating commons 2023-05-15 20:43:31 +02:00
Tibor Kaputa 16965fb357
Merge pull request #196 from weblate/weblate-simple-mobile-tools-simple-flashlight
Translations update from Hosted Weblate
2023-05-15 20:37:16 +02:00
Макар Разин 70188d7731
Translated using Weblate (Belarusian)
Currently translated at 100.0% (9 of 9 strings)

Translation: Simple Mobile Tools/Simple Flashlight
Translate-URL: https://hosted.weblate.org/projects/simple-mobile-tools/simple-flashlight/be/
2023-05-10 23:48:31 +02:00
Slávek Banko 94b8ec3f19
Translated using Weblate (Czech)
Currently translated at 100.0% (8 of 8 strings)

Translation: Simple Mobile Tools/Simple Flashlight metadata
Translate-URL: https://hosted.weblate.org/projects/simple-mobile-tools/simple-flashlight-metadata/cs/
2023-03-31 18:41:32 +02:00
tibbi a0cfafb7b1 updating changelog 2023-03-25 12:23:18 +01:00
tibbi a92a4bf23a update version to 5.9.1 2023-03-25 12:23:11 +01:00
tibbi 4bc55c1282 updating commons 2023-03-25 12:19:21 +01:00
Tibor Kaputa dd78bfe8ba
Merge pull request #189 from fedestyla/fix/165_flashlight-on-after-camera-usage
fix(#165): fix flashlight status after coming back from camera app
2023-03-25 10:10:18 +01:00
Tibor Kaputa 3ecad0db58
Merge pull request #188 from weblate/weblate-simple-mobile-tools-simple-flashlight
Translations update from Hosted Weblate
2023-03-25 09:54:14 +01:00
Tibor Kaputa c44a619cec
Update title.txt 2023-03-25 09:54:05 +01:00
VfBFan 5fbdcb3904
Translated using Weblate (German)
Currently translated at 100.0% (9 of 9 strings)

Translation: Simple Mobile Tools/Simple Flashlight
Translate-URL: https://hosted.weblate.org/projects/simple-mobile-tools/simple-flashlight/de/
2023-03-21 10:36:58 +01:00
P.O eaeca0920c
Translated using Weblate (Swedish)
Currently translated at 100.0% (7 of 7 strings)

Translation: Simple Mobile Tools/Simple Flashlight metadata
Translate-URL: https://hosted.weblate.org/projects/simple-mobile-tools/simple-flashlight-metadata/sv/
2023-03-12 17:42:44 +01:00
Oğuz Ersen 48892c6f13
Translated using Weblate (Turkish)
Currently translated at 100.0% (7 of 7 strings)

Translation: Simple Mobile Tools/Simple Flashlight metadata
Translate-URL: https://hosted.weblate.org/projects/simple-mobile-tools/simple-flashlight-metadata/tr/
2023-02-21 19:40:35 +01:00
Rex_sa f3ff2ae894
Translated using Weblate (Arabic)
Currently translated at 100.0% (7 of 7 strings)

Translation: Simple Mobile Tools/Simple Flashlight metadata
Translate-URL: https://hosted.weblate.org/projects/simple-mobile-tools/simple-flashlight-metadata/ar/
2023-02-18 12:27:21 +01:00
Tibor Kaputa e7070ff04b
Update CONTRIBUTING.md 2023-02-18 12:27:17 +01:00
tibbi 37a6216b5b adding contribution rules 2023-02-17 22:41:11 +01:00
Federico Palmieri a84c22ebf8 fix(#165): fix flashlight status after coming back from camera app 2023-02-14 18:45:15 +01:00
tibbi 017d9f7557 do not show More Apps From Us as an icon 2023-02-10 19:08:37 +01:00
tibbi 5d9dc308d2 removing all video.txt files 2023-01-15 23:25:26 +01:00
Tibor Kaputa 3e0f578f6f
Merge pull request #183 from weblate/weblate-simple-mobile-tools-simple-flashlight
Translations update from Hosted Weblate
2023-01-15 13:09:44 +01:00
Linerly e8b29984ac
Translated using Weblate (Indonesian)
Currently translated at 100.0% (8 of 8 strings)

Translation: Simple Mobile Tools/Simple Flashlight metadata
Translate-URL: https://hosted.weblate.org/projects/simple-mobile-tools/simple-flashlight-metadata/id/
2023-01-13 00:51:40 +01:00
Sergio Marques 2d60a5df05
Translated using Weblate (Portuguese)
Currently translated at 100.0% (9 of 9 strings)

Translation: Simple Mobile Tools/Simple Flashlight
Translate-URL: https://hosted.weblate.org/projects/simple-mobile-tools/simple-flashlight/pt/
2023-01-13 00:51:40 +01:00
Ahmad0a 4380996d0b
Translated using Weblate (Arabic)
Currently translated at 100.0% (8 of 8 strings)

Translation: Simple Mobile Tools/Simple Flashlight metadata
Translate-URL: https://hosted.weblate.org/projects/simple-mobile-tools/simple-flashlight-metadata/ar/
2023-01-06 23:51:27 +01:00
Milo Ivir ac5b03820c
Translated using Weblate (Croatian)
Currently translated at 100.0% (8 of 8 strings)

Translation: Simple Mobile Tools/Simple Flashlight metadata
Translate-URL: https://hosted.weblate.org/projects/simple-mobile-tools/simple-flashlight-metadata/hr/
2023-01-05 22:51:20 +01:00
Dan 53060d644b
Translated using Weblate (Ukrainian)
Currently translated at 100.0% (8 of 8 strings)

Translation: Simple Mobile Tools/Simple Flashlight metadata
Translate-URL: https://hosted.weblate.org/projects/simple-mobile-tools/simple-flashlight-metadata/uk/
2022-12-28 23:51:01 +01:00
Dan 71e0120842
Translated using Weblate (Ukrainian)
Currently translated at 87.5% (7 of 8 strings)

Translation: Simple Mobile Tools/Simple Flashlight metadata
Translate-URL: https://hosted.weblate.org/projects/simple-mobile-tools/simple-flashlight-metadata/uk/
2022-12-27 17:01:45 +01:00
tibbi f6827cec6d updating commons 2022-12-27 17:01:38 +01:00
tibbi 69eac399db updating changelog 2022-12-21 10:33:59 +01:00
tibbi 3eb2055c48 update version to 5.9.0 2022-12-21 10:33:53 +01:00
tibbi 1edb546cbb tweaking the bright display vector 2022-12-21 10:22:43 +01:00
tibbi 0886fe368a use a vector icon for stroboscope too 2022-12-21 10:08:23 +01:00
tibbi 6f8db7c15c use a vector asset for flashlight icon 2022-12-21 10:06:32 +01:00
tibbi f51efb05cc use a vector asset for bright display 2022-12-21 10:01:22 +01:00
tibbi cc156d4152 remove the toolbar at widget config screens 2022-12-20 23:32:13 +01:00
tibbi f82331559c redesigning some screens 2022-12-20 19:20:45 +01:00
tibbi b96e268a45 removing a redundant interface 2022-12-20 18:58:59 +01:00
Tibor Kaputa b9f180d9d2
Merge pull request #182 from weblate/weblate-simple-mobile-tools-simple-flashlight
Translations update from Hosted Weblate
2022-12-20 18:57:37 +01:00
Josep M. Ferrer 7c8f3f2553
Translated using Weblate (Catalan)
Currently translated at 100.0% (7 of 7 strings)

Translation: Simple Mobile Tools/Simple Flashlight metadata
Translate-URL: https://hosted.weblate.org/projects/simple-mobile-tools/simple-flashlight-metadata/ca/
2022-12-20 18:55:40 +01:00
Dan 43d6c66fd8
Translated using Weblate (Ukrainian)
Currently translated at 100.0% (7 of 7 strings)

Translation: Simple Mobile Tools/Simple Flashlight metadata
Translate-URL: https://hosted.weblate.org/projects/simple-mobile-tools/simple-flashlight-metadata/uk/
2022-12-20 18:55:40 +01:00
Josep M. Ferrer da5b1061f8
Translated using Weblate (German)
Currently translated at 100.0% (7 of 7 strings)

Translation: Simple Mobile Tools/Simple Flashlight metadata
Translate-URL: https://hosted.weblate.org/projects/simple-mobile-tools/simple-flashlight-metadata/de/
2022-12-20 18:55:40 +01:00
Agnieszka C e9015fa7a6
Translated using Weblate (Polish)
Currently translated at 100.0% (7 of 7 strings)

Translation: Simple Mobile Tools/Simple Flashlight metadata
Translate-URL: https://hosted.weblate.org/projects/simple-mobile-tools/simple-flashlight-metadata/pl/
2022-12-20 18:55:40 +01:00
rehork 8d502ef28e
Translated using Weblate (Polish)
Currently translated at 85.7% (6 of 7 strings)

Translation: Simple Mobile Tools/Simple Flashlight metadata
Translate-URL: https://hosted.weblate.org/projects/simple-mobile-tools/simple-flashlight-metadata/pl/
2022-12-20 18:55:40 +01:00
tibbi 869fb11171 updating commons, set minimal Android version to 6 2022-12-20 18:55:33 +01:00
Tibor Kaputa dcb34c2f08
Merge pull request #179 from weblate/weblate-simple-mobile-tools-simple-flashlight
Translations update from Hosted Weblate
2022-12-09 23:00:16 +01:00
Tibor Kaputa c3f8b6213e
Update short_description.txt 2022-12-09 23:00:09 +01:00
VfBFan ff7ae31750
Translated using Weblate (German)
Currently translated at 100.0% (7 of 7 strings)

Translation: Simple Mobile Tools/Simple Flashlight metadata
Translate-URL: https://hosted.weblate.org/projects/simple-mobile-tools/simple-flashlight-metadata/de/
2022-11-22 21:47:56 +01:00
Martin Božič b5af7cf0a3
Translated using Weblate (Slovenian)
Currently translated at 100.0% (7 of 7 strings)

Translation: Simple Mobile Tools/Simple Flashlight metadata
Translate-URL: https://hosted.weblate.org/projects/simple-mobile-tools/simple-flashlight-metadata/sl/
2022-11-21 11:47:42 +01:00
tibbi 3602ac5bb1 updating changelog 2022-11-17 23:37:22 +01:00
tibbi e114faef5a update version to 5.8.4 2022-11-17 23:37:15 +01:00
tibbi e28525f23c adding some crashfixes 2022-11-17 23:32:48 +01:00
Tibor Kaputa 128f01c751
Merge pull request #178 from weblate/weblate-simple-mobile-tools-simple-flashlight
Translations update from Hosted Weblate
2022-11-17 23:32:27 +01:00
Martin Božič 372c6b61d4
Translated using Weblate (Slovenian)
Currently translated at 100.0% (6 of 6 strings)

Translation: Simple Mobile Tools/Simple Flashlight metadata
Translate-URL: https://hosted.weblate.org/projects/simple-mobile-tools/simple-flashlight-metadata/sl/
2022-11-17 08:47:54 +01:00
tibbi c3996388f4 updating changelog 2022-11-15 16:03:56 +01:00
tibbi 93bda81af4 update version to 5.8.3 2022-11-15 16:03:49 +01:00
tibbi 2dc20b3ac9 show a More apps from us menu button at the top menu 2022-11-15 15:59:43 +01:00
Tibor Kaputa 858533e991
Merge pull request #174 from KryptKode/feat/brightness-control
Add torch brightness level support for Android 13+
2022-11-15 15:37:41 +01:00
darthpaul c975ab1e82 clear listeners after disabling flash for SOS and stroboscope
- this prevents the two sliders for brightness and stroboscope from showing up at the same time
2022-11-15 14:28:35 +00:00
darthpaul 98c0f0578e cleanup flash implementation
- fix issues with brightness control
- add separate classes for Android 5 and Android 6+ for simplicity
- properly cleanup camera in onDestory and also when stroboscope/flashlight mode are disabled
2022-11-14 19:17:00 +00:00
Tibor Kaputa f20341d920
Merge pull request #177 from weblate/weblate-simple-mobile-tools-simple-flashlight
Translations update from Hosted Weblate
2022-11-14 14:58:52 +01:00
Tibor Kaputa cf75472344
Delete video.txt 2022-11-14 14:58:42 +01:00
Alex 83ee3b0eb6
Translated using Weblate (Serbian)
Currently translated at 100.0% (5 of 5 strings)

Translation: Simple Mobile Tools/Simple Flashlight metadata
Translate-URL: https://hosted.weblate.org/projects/simple-mobile-tools/simple-flashlight-metadata/sr/
2022-11-14 14:01:55 +01:00
darthpaul 87b678e4bb show/hide brightness seekbar from camera callback 2022-11-09 09:36:08 +00:00
Tibor Kaputa 0e726d7d1c
Merge pull request #173 from Mikkel-T/fix-sos-timing
Fix SOS timing
2022-11-08 11:09:50 +01:00
tibbi 662ec91227 updating commons and gradle 2022-11-08 11:05:38 +01:00
Tibor Kaputa f52c9299fe
Merge pull request #176 from weblate/weblate-simple-mobile-tools-simple-flashlight
Translations update from Hosted Weblate
2022-11-08 11:04:38 +01:00
Tibor Kaputa b5b7a562bb
Delete video.txt 2022-11-08 11:04:12 +01:00
Tibor Kaputa 47c8dc34f7
Update strings.xml 2022-11-08 11:03:42 +01:00
Alex 780e4c8b53
Translated using Weblate (Serbian)
Currently translated at 100.0% (9 of 9 strings)

Translation: Simple Mobile Tools/Simple Flashlight
Translate-URL: https://hosted.weblate.org/projects/simple-mobile-tools/simple-flashlight/sr/
2022-11-07 22:02:09 +01:00
Alex 87f96b2aa9
Translated using Weblate (Serbian)
Currently translated at 77.7% (7 of 9 strings)

Translation: Simple Mobile Tools/Simple Flashlight
Translate-URL: https://hosted.weblate.org/projects/simple-mobile-tools/simple-flashlight/sr/
2022-11-06 21:09:12 +01:00
Anonymous b31152875d
Translated using Weblate (Serbian)
Currently translated at 100.0% (0 of 0 strings)

Translation: Simple Mobile Tools/Simple Flashlight
Translate-URL: https://hosted.weblate.org/projects/simple-mobile-tools/simple-flashlight/sr/
2022-11-06 21:04:52 +01:00
Alex 06bca5ab99
Added translation using Weblate (Serbian) 2022-11-06 21:04:48 +01:00
gallegonovato 0d86e64314
Translated using Weblate (Spanish)
Currently translated at 80.0% (4 of 5 strings)

Translation: Simple Mobile Tools/Simple Flashlight metadata
Translate-URL: https://hosted.weblate.org/projects/simple-mobile-tools/simple-flashlight-metadata/es/
2022-11-05 21:04:40 +01:00
Alex 770616298f
Translated using Weblate (Croatian)
Currently translated at 100.0% (5 of 5 strings)

Translation: Simple Mobile Tools/Simple Flashlight metadata
Translate-URL: https://hosted.weblate.org/projects/simple-mobile-tools/simple-flashlight-metadata/hr/
2022-11-05 09:51:34 +01:00
Tibor Kaputa 25a72290ea
Merge pull request #175 from KryptKode/feat/bright-display-tile
Add Bright Display settings tile
2022-11-05 09:51:30 +01:00
tibbi a8584c1f42 removing some custom app icons 2022-11-01 23:19:51 +01:00
Tibor Kaputa f66155cb3d
Merge pull request #172 from weblate/weblate-simple-mobile-tools-simple-flashlight
Translations update from Hosted Weblate
2022-10-29 12:06:16 +02:00
Tibor Kaputa 55eb0a297e
Delete video.txt 2022-10-29 12:04:10 +02:00
Tibor Kaputa 1489c89736
Update strings.xml 2022-10-29 12:02:49 +02:00
Tibor Kaputa 5be7abc86a
Update strings.xml 2022-10-29 12:02:30 +02:00
Tibor Kaputa fca50455d2
Update strings.xml 2022-10-29 12:02:13 +02:00
Anonymous bda82d00f5
Translated using Weblate (Icelandic)
Currently translated at 100.0% (0 of 0 strings)

Translation: Simple Mobile Tools/Simple Flashlight
Translate-URL: https://hosted.weblate.org/projects/simple-mobile-tools/simple-flashlight/is/
2022-10-28 14:26:11 +02:00
Trendyne 94cd66aadf
Added translation using Weblate (Icelandic) 2022-10-28 14:26:05 +02:00
bgo-eiu a85eeec1a2
Translated using Weblate (Punjabi (Pakistan))
Currently translated at 100.0% (9 of 9 strings)

Translation: Simple Mobile Tools/Simple Flashlight
Translate-URL: https://hosted.weblate.org/projects/simple-mobile-tools/simple-flashlight/pa_PK/
2022-10-27 09:35:10 +02:00
Anonymous 4e452be4a4
Translated using Weblate (Punjabi (Pakistan))
Currently translated at 100.0% (0 of 0 strings)

Translation: Simple Mobile Tools/Simple Flashlight
Translate-URL: https://hosted.weblate.org/projects/simple-mobile-tools/simple-flashlight/pa_PK/
2022-10-27 09:12:31 +02:00
bgo-eiu 1b4102b80c
Added translation using Weblate (Punjabi (Pakistan)) 2022-10-27 09:12:22 +02:00
darthpaul 75eca9e3f0 set brightness level to maximum by default 2022-10-26 14:16:27 +01:00
Alex e3b8b943e2
Translated using Weblate (Slovenian)
Currently translated at 100.0% (5 of 5 strings)

Translation: Simple Mobile Tools/Simple Flashlight metadata
Translate-URL: https://hosted.weblate.org/projects/simple-mobile-tools/simple-flashlight-metadata/sl/
2022-10-26 09:27:46 +02:00
Alex b313a2f33b
Translated using Weblate (Slovenian)
Currently translated at 100.0% (9 of 9 strings)

Translation: Simple Mobile Tools/Simple Flashlight
Translate-URL: https://hosted.weblate.org/projects/simple-mobile-tools/simple-flashlight/sl/
2022-10-24 21:04:05 +02:00
Rex_sa 2bfeda0041
Translated using Weblate (Arabic)
Currently translated at 100.0% (9 of 9 strings)

Translation: Simple Mobile Tools/Simple Flashlight
Translate-URL: https://hosted.weblate.org/projects/simple-mobile-tools/simple-flashlight/ar/
2022-10-24 21:04:05 +02:00
darthpaul 28bda12ae9 Add Bright Display settings tile 2022-10-23 09:50:04 +01:00
darthpaul cea57e9db0 Add torch brightness level support for Android 13+ 2022-10-23 09:03:16 +01:00
Anonymous acc834ca46
Translated using Weblate (Slovenian)
Currently translated at 100.0% (0 of 0 strings)

Translation: Simple Mobile Tools/Simple Flashlight
Translate-URL: https://hosted.weblate.org/projects/simple-mobile-tools/simple-flashlight/sl/
2022-10-22 21:40:42 +02:00
Alex 39339cf973
Added translation using Weblate (Slovenian) 2022-10-22 21:40:38 +02:00
Vri 🌈 dfa252f1ab
Translated using Weblate (German)
Currently translated at 100.0% (5 of 5 strings)

Translation: Simple Mobile Tools/Simple Flashlight metadata
Translate-URL: https://hosted.weblate.org/projects/simple-mobile-tools/simple-flashlight-metadata/de/
2022-10-21 12:01:30 +02:00
Mikkel-T b67d42a9d0 Fix SOS timing
Changes the SOS timing to use the lengths as described here: https://en.wikipedia.org/wiki/Morse_code#Representation,_timing,_and_speeds
Also change the unit to 200 instead of 250
2022-10-19 16:16:11 +02:00
gallegonovato f2595cf15b
Translated using Weblate (Spanish)
Currently translated at 80.0% (4 of 5 strings)

Translation: Simple Mobile Tools/Simple Flashlight metadata
Translate-URL: https://hosted.weblate.org/projects/simple-mobile-tools/simple-flashlight-metadata/es/
2022-10-19 14:01:06 +02:00
NPL a0f3d6a6fe
Translated using Weblate (Japanese)
Currently translated at 80.0% (4 of 5 strings)

Translation: Simple Mobile Tools/Simple Flashlight metadata
Translate-URL: https://hosted.weblate.org/projects/simple-mobile-tools/simple-flashlight-metadata/ja/
2022-10-10 20:06:15 +02:00
gallegonovato 671dcd330f
Translated using Weblate (Spanish)
Currently translated at 80.0% (4 of 5 strings)

Translation: Simple Mobile Tools/Simple Flashlight metadata
Translate-URL: https://hosted.weblate.org/projects/simple-mobile-tools/simple-flashlight-metadata/es/
2022-10-10 20:06:15 +02:00
gallegonovato 0d2025fdd0
Translated using Weblate (Galician)
Currently translated at 100.0% (9 of 9 strings)

Translation: Simple Mobile Tools/Simple Flashlight
Translate-URL: https://hosted.weblate.org/projects/simple-mobile-tools/simple-flashlight/gl/
2022-10-10 20:06:15 +02:00
gallegonovato a2016cc454
Translated using Weblate (Spanish)
Currently translated at 100.0% (9 of 9 strings)

Translation: Simple Mobile Tools/Simple Flashlight
Translate-URL: https://hosted.weblate.org/projects/simple-mobile-tools/simple-flashlight/es/
2022-10-10 20:06:14 +02:00
tibbi dc66f8bd66 adding the fastlane changelog too 2022-10-06 16:28:42 +02:00
tibbi 594b227ab2 updating changelog 2022-10-06 16:28:00 +02:00
tibbi 8c20fdbced update version to 5.8.2 2022-10-06 16:27:55 +02:00
tibbi 610d9e6728 updating commons 2022-10-06 16:24:10 +02:00
tibbi e18c4b9541 updating commons 2022-10-06 14:43:45 +02:00
Tibor Kaputa e533af5e1c
Merge pull request #171 from weblate/weblate-simple-mobile-tools-simple-flashlight
Translations update from Hosted Weblate
2022-10-06 14:41:35 +02:00
paula katos ce297ccd11
Translated using Weblate (Romanian)
Currently translated at 75.0% (3 of 4 strings)

Translation: Simple Mobile Tools/Simple Flashlight metadata
Translate-URL: https://hosted.weblate.org/projects/simple-mobile-tools/simple-flashlight-metadata/ro/
2022-10-05 14:23:30 +02:00
atilluF a7589478e4
Translated using Weblate (Italian)
Currently translated at 100.0% (9 of 9 strings)

Translation: Simple Mobile Tools/Simple Flashlight
Translate-URL: https://hosted.weblate.org/projects/simple-mobile-tools/simple-flashlight/it/
2022-10-04 21:06:38 +02:00
en2sv 17914a9220
Translated using Weblate (Swedish)
Currently translated at 100.0% (9 of 9 strings)

Translation: Simple Mobile Tools/Simple Flashlight
Translate-URL: https://hosted.weblate.org/projects/simple-mobile-tools/simple-flashlight/sv/
2022-09-25 13:23:14 +02:00
tibbi 73a81d533d renaming some fastlane folders 2022-09-22 23:04:53 +02:00
Tibor Kaputa 14116b9031
Merge pull request #170 from weblate/weblate-simple-mobile-tools-simple-flashlight
Translations update from Hosted Weblate
2022-09-22 23:03:14 +02:00
words wave cdf3b77a3e
Translated using Weblate (Finnish)
Currently translated at 75.0% (3 of 4 strings)

Translation: Simple Mobile Tools/Simple Flashlight metadata
Translate-URL: https://hosted.weblate.org/projects/simple-mobile-tools/simple-flashlight-metadata/fi/
2022-09-22 12:19:39 +02:00
words wave 3dfca24a94
Translated using Weblate (Estonian)
Currently translated at 75.0% (3 of 4 strings)

Translation: Simple Mobile Tools/Simple Flashlight metadata
Translate-URL: https://hosted.weblate.org/projects/simple-mobile-tools/simple-flashlight-metadata/et/
2022-09-18 19:19:08 +02:00
words wave 9a22d24516
Translated using Weblate (Finnish)
Currently translated at 100.0% (9 of 9 strings)

Translation: Simple Mobile Tools/Simple Flashlight
Translate-URL: https://hosted.weblate.org/projects/simple-mobile-tools/simple-flashlight/fi/
2022-09-18 19:19:08 +02:00
Kovacs Bea d2cdb3af06
Translated using Weblate (Hungarian)
Currently translated at 75.0% (3 of 4 strings)

Translation: Simple Mobile Tools/Simple Flashlight metadata
Translate-URL: https://hosted.weblate.org/projects/simple-mobile-tools/simple-flashlight-metadata/hu/
2022-09-16 11:21:18 +02:00
Kovacs Bea 1bd651480d
Translated using Weblate (Hungarian)
Currently translated at 100.0% (4 of 4 strings)

Translation: Simple Mobile Tools/Simple Flashlight metadata
Translate-URL: https://hosted.weblate.org/projects/simple-mobile-tools/simple-flashlight-metadata/hu/
2022-09-14 19:41:01 +02:00
Milo Ivir 6f82830a36
Translated using Weblate (Croatian)
Currently translated at 100.0% (4 of 4 strings)

Translation: Simple Mobile Tools/Simple Flashlight metadata
Translate-URL: https://hosted.weblate.org/projects/simple-mobile-tools/simple-flashlight-metadata/hr/
2022-09-14 19:41:01 +02:00
Stefan Ivanov f74d16c42c
Translated using Weblate (Bulgarian)
Currently translated at 75.0% (3 of 4 strings)

Translation: Simple Mobile Tools/Simple Flashlight metadata
Translate-URL: https://hosted.weblate.org/projects/simple-mobile-tools/simple-flashlight-metadata/bg/
2022-09-14 19:41:01 +02:00
Stefan Ivanov de51245a89
Translated using Weblate (Bulgarian)
Currently translated at 100.0% (9 of 9 strings)

Translation: Simple Mobile Tools/Simple Flashlight
Translate-URL: https://hosted.weblate.org/projects/simple-mobile-tools/simple-flashlight/bg/
2022-09-14 19:41:01 +02:00
Stefan Ivanov f82d664078
Translated using Weblate (Russian)
Currently translated at 100.0% (9 of 9 strings)

Translation: Simple Mobile Tools/Simple Flashlight
Translate-URL: https://hosted.weblate.org/projects/simple-mobile-tools/simple-flashlight/ru/
2022-09-14 19:41:01 +02:00
Josep M. Ferrer 3f2fd4751d
Translated using Weblate (Catalan)
Currently translated at 100.0% (4 of 4 strings)

Translation: Simple Mobile Tools/Simple Flashlight metadata
Translate-URL: https://hosted.weblate.org/projects/simple-mobile-tools/simple-flashlight-metadata/ca/
2022-09-14 19:41:01 +02:00
Agnieszka C 3205c422ea
Translated using Weblate (Polish)
Currently translated at 100.0% (4 of 4 strings)

Translation: Simple Mobile Tools/Simple Flashlight metadata
Translate-URL: https://hosted.weblate.org/projects/simple-mobile-tools/simple-flashlight-metadata/pl/
2022-09-14 19:41:00 +02:00
tibbi 43c4bbb0a1 move widget preview images into drawable-nodpi 2022-09-14 19:40:53 +02:00
tibbi 9931cd43c4 updating changelog 2022-09-11 22:06:13 +02:00
tibbi f039ec9f40 update version to 5.8.1 2022-09-11 22:06:07 +02:00
tibbi 5713537fc9 updating commons 2022-09-11 22:01:31 +02:00
tibbi d73a5f17c6 syncing fastlane files with google play 2022-09-11 21:52:38 +02:00
Tibor Kaputa b884038062
Merge pull request #169 from weblate/weblate-simple-mobile-tools-simple-flashlight
Translations update from Hosted Weblate
2022-09-11 21:36:13 +02:00
Priit Jõerüüt 41dcf874e9
Translated using Weblate (Estonian)
Currently translated at 75.0% (3 of 4 strings)

Translation: Simple Mobile Tools/Simple Flashlight metadata
Translate-URL: https://hosted.weblate.org/projects/simple-mobile-tools/simple-flashlight-metadata/et/
2022-09-07 20:20:31 +02:00
Worldfast 51293cd85c
Translated using Weblate (Turkish)
Currently translated at 75.0% (3 of 4 strings)

Translation: Simple Mobile Tools/Simple Flashlight metadata
Translate-URL: https://hosted.weblate.org/projects/simple-mobile-tools/simple-flashlight-metadata/tr/
2022-09-04 12:10:04 +02:00
gallegonovato 1460e80297
Translated using Weblate (Spanish)
Currently translated at 75.0% (3 of 4 strings)

Translation: Simple Mobile Tools/Simple Flashlight metadata
Translate-URL: https://hosted.weblate.org/projects/simple-mobile-tools/simple-flashlight-metadata/es/
2022-09-04 12:10:03 +02:00
kyoya 64a4bccf37
Translated using Weblate (Turkish)
Currently translated at 75.0% (3 of 4 strings)

Translation: Simple Mobile Tools/Simple Flashlight metadata
Translate-URL: https://hosted.weblate.org/projects/simple-mobile-tools/simple-flashlight-metadata/tr/
2022-09-04 07:51:20 +02:00
gallegonovato aa118984c0
Translated using Weblate (Spanish)
Currently translated at 100.0% (4 of 4 strings)

Translation: Simple Mobile Tools/Simple Flashlight metadata
Translate-URL: https://hosted.weblate.org/projects/simple-mobile-tools/simple-flashlight-metadata/es/
2022-09-01 21:23:42 +02:00
Josep M. Ferrer c4e40501b5
Translated using Weblate (Catalan)
Currently translated at 100.0% (4 of 4 strings)

Translation: Simple Mobile Tools/Simple Flashlight metadata
Translate-URL: https://hosted.weblate.org/projects/simple-mobile-tools/simple-flashlight-metadata/ca/
2022-08-31 00:23:27 +02:00
Milo Ivir 14ed2c2c3a
Translated using Weblate (Croatian)
Currently translated at 100.0% (4 of 4 strings)

Translation: Simple Mobile Tools/Simple Flashlight metadata
Translate-URL: https://hosted.weblate.org/projects/simple-mobile-tools/simple-flashlight-metadata/hr/
2022-08-29 12:54:51 +02:00
tibbi 1c43813762 properly handle monochrone icon with any colored icon 2022-08-29 12:54:45 +02:00
tibbi f33c0d611c update language changer ripple in some cases 2022-08-18 22:07:36 +02:00
tibbi 3a65836e76 scroll the settings too 2022-08-17 21:49:46 +02:00
333 changed files with 3093 additions and 1582 deletions

View File

@ -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)*
----------------------------

8
CONTRIBUTING.md Normal file
View File

@ -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).

View 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>

View File

@ -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'
}

111
app/build.gradle.kts Normal file
View File

@ -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)
}

View File

@ -1,6 +0,0 @@
# EventBus
-keepattributes *Annotation*
-keepclassmembers class ** {
@org.greenrobot.eventbus.Subscribe <methods>;
}
-keep enum org.greenrobot.eventbus.ThreadMode { *; }

View File

@ -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"

View File

@ -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
}
}
}

View File

@ -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()
}
}
}

View File

@ -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
}
}
}

View File

@ -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) {}
}
}

View File

@ -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) {}
}
}

View File

@ -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
}
}

View File

@ -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 = {},
)
}
}

View File

@ -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()
}
}
}

View File

@ -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
}

View File

@ -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)
}
}

View File

@ -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
}
}

View File

@ -0,0 +1,7 @@
package com.simplemobiletools.flashlight.helpers
interface CameraTorchListener {
fun onTorchEnabled(isEnabled:Boolean)
fun onTorchUnavailable()
}

View File

@ -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()
}

View File

@ -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

View File

@ -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()

View File

@ -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)
}
}
}

View File

@ -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)
}

View File

@ -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)
}
}

View File

@ -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)
}
}

View File

@ -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)
}
}

View File

@ -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)

View File

@ -1,11 +0,0 @@
package com.simplemobiletools.flashlight.models
class Events {
class StateChanged(val isEnabled: Boolean)
class CameraUnavailable
class StopStroboscope
class StopSOS
}

View File

@ -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 = {},
)
}
}

View File

@ -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 = {}
)
}
}

View File

@ -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 = {},
)
}
}

View File

@ -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 = {}
)
}
}

View File

@ -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 = {}
)
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

View File

Before

Width:  |  Height:  |  Size: 2.7 KiB

After

Width:  |  Height:  |  Size: 2.7 KiB

View File

Before

Width:  |  Height:  |  Size: 4.0 KiB

After

Width:  |  Height:  |  Size: 4.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.6 KiB

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

Some files were not shown because too many files have changed in this diff Show More