Skip to content

Commit fedfeaf

Browse files
committed
added picture in picture support
Change-Id: I83fdb69e0aedc9f352d7b13daabdbb0f324c81d5 Signed-off-by: AbdAlMoniem AlHifnawy <hifnawy_moniem@hotmail.com>
1 parent 22a5ce6 commit fedfeaf

File tree

19 files changed

+631
-148
lines changed

19 files changed

+631
-148
lines changed

.github/workflows/build_debug_variant.yml

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,6 @@ jobs:
2020
steps:
2121
- uses: actions/checkout@v4
2222

23-
- name: Check base64
24-
run: base64 --version
25-
2623
- name: Create local.properties
2724
run: |
2825
echo ${{ secrets.SIGNING_KEY }} | base64 -d > release_keystore.jks

.github/workflows/build_release_variant.yml

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,6 @@ jobs:
1616
steps:
1717
- uses: actions/checkout@v4
1818

19-
- name: Check base64
20-
run: base64 --version
21-
2219
- name: Create local.properties
2320
run: |
2421
echo ${{ secrets.SIGNING_KEY }} | base64 -d > release_keystore.jks
Lines changed: 21 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
#file: noinspection Annotator
22
name: Publish Release By Tag
3-
run-name: ${{ github.workflow }} Tag ${{ inputs.releaseTag }}
3+
run-name: ${{ github.workflow }} ${{ inputs.releaseTag }} ${{ github.event.repository.updated_at}}
44
on:
55
workflow_dispatch:
66
inputs:
@@ -9,6 +9,7 @@ on:
99
required: true
1010
type: choice
1111
options:
12+
- v2.0.0
1213
- v1.8.0
1314
- v1.7.5
1415
- v1.7.2
@@ -39,31 +40,19 @@ on:
3940
- v1.1.1
4041
- v1.1
4142
- v1.0
42-
logLevel:
43-
description: 'Log level'
44-
required: true
45-
default: 'info'
46-
type: choice
47-
options:
48-
- info
49-
- warning
50-
- debug
51-
permissions: {}
43+
44+
permissions: { }
45+
5246
jobs:
5347
publish-release-by-tag:
5448
name: Publish Release By Tag
5549
runs-on: ubuntu-latest
5650
steps:
5751
- name: Checkout Tag ${{ inputs.releaseTag }}
5852
uses: actions/checkout@v4
59-
env:
60-
LEVEL: ${{ inputs.logLevel }}
6153
with:
6254
ref: refs/tags/${{ inputs.releaseTag }}
63-
- name: Check base64
64-
env:
65-
LEVEL: ${{ inputs.logLevel }}
66-
run: base64 --version
55+
6756
- name: Create local.properties
6857
run: |
6958
echo ${{ secrets.SIGNING_KEY }} | base64 -d > release_keystore.jks
@@ -76,55 +65,51 @@ jobs:
7665
echo "keyPassword=${{ secrets.KEY_PASSWORD }}" >> local.properties
7766
echo "keyAlias=release_key" >> local.properties
7867
echo "storeFile=$keystoreFile" >> local.properties
68+
7969
- name: Setup Java
8070
uses: actions/setup-java@v4
81-
env:
82-
LEVEL: ${{ inputs.logLevel }}
8371
with:
8472
distribution: 'adopt'
8573
java-version: 21
74+
8675
- name: Validate Gradle Wrapper
8776
uses: gradle/wrapper-validation-action@v2.1.3
88-
env:
89-
LEVEL: ${{ inputs.logLevel }}
77+
9078
- name: Build APKs
91-
env:
92-
LEVEL: ${{ inputs.logLevel }}
9379
run: |
9480
ls
9581
bash gradlew app:assembleRelease
82+
9683
- name: Get Release APK Name
97-
env:
98-
LEVEL: ${{ inputs.logLevel }}
9984
run: |
10085
releaseApk=$(find app/build/outputs/apk/release/*.apk)
10186
echo $releaseApk
10287
echo ARTIFACT_NAME=$(basename $releaseApk) >> $GITHUB_ENV
10388
echo ARTIFACT_PATH=$releaseApk >> $GITHUB_ENV
89+
10490
- name: Create Artifact ${{ env.ARTIFACT_NAME }}
10591
uses: actions/upload-artifact@v4
106-
env:
107-
LEVEL: ${{ inputs.logLevel }}
10892
with:
10993
name: ${{ env.ARTIFACT_NAME }}
11094
path: ${{ env.ARTIFACT_PATH }}
11195
if-no-files-found: error
96+
11297
- name: Get Commit Message
113-
env:
114-
LEVEL: ${{ inputs.logLevel }}
11598
run: |
116-
echo "COMMIT_MESSAGE=$(git show -s --format=%B)"
99+
gitTopLevel="$(git rev-parse --show-toplevel)"
100+
versionCodeFilter="\(versionCode\s\+=\s\+\)\([[:digit:]]\+\)"
101+
versionCode=$(git show "$tag:app/build.gradle.kts" | grep versionCode | sed -e "s/$versionCodeFilter/\2/" | xargs)
102+
103+
cat "$gitTopLevel/fastlane/metadata/android/en-US/changelogs/$versionCode.txt"
104+
117105
{
118106
echo 'COMMIT_MESSAGE<<EOF'
119-
git show -s --format=%B | sed -e 's/Change-Id:\s*\w\+//' | sed -e 's/Signed-off-by:\s*.*//' | sed ':a;N;$!ba;s/\n*$//'
107+
cat "$gitTopLevel/fastlane/metadata/android/en-US/changelogs/$versionCode.txt"
120108
echo EOF
121109
} >> $GITHUB_ENV
122-
- name: Publish Release ${{ inputs.releaseTag }}
123-
# noinspection SpellCheckingInspection
124110
111+
- name: Publish Release ${{ github.ref_name }}
125112
uses: svenstaro/upload-release-action@v2
126-
env:
127-
LEVEL: ${{ inputs.logLevel }}
128113
with:
129114
file: ${{ env.ARTIFACT_PATH }}
130115
tag: refs/tags/${{ inputs.releaseTag }}
@@ -134,4 +119,4 @@ jobs:
134119
make_latest: true
135120
body: ${{ env.COMMIT_MESSAGE }}
136121
release_name: ${{ inputs.releaseTag }}
137-
repo_token: ${{ secrets.RELEASE_GITHUB_TOKEN }}
122+
repo_token: ${{ secrets.RELEASE_GITHUB_TOKEN }}

.github/workflows/publish_release_on_tag.yml

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
#file: noinspection Annotator
22
name: Publish Release On Tag
3-
run-name: ${{ github.workflow }} ${{ github.ref_name }}
3+
run-name: ${{ github.workflow }} ${{ github.ref_name }} ${{ github.event.repository.updated_at}}
44

55
on:
66
push:
@@ -19,9 +19,6 @@ jobs:
1919
- name: Checkout ${{ github.ref }}
2020
uses: actions/checkout@v4
2121

22-
- name: Check base64
23-
run: base64 --version
24-
2522
- name: Create local.properties
2623
run: |
2724
echo ${{ secrets.SIGNING_KEY }} | base64 -d > release_keystore.jks
@@ -63,15 +60,19 @@ jobs:
6360

6461
- name: Get Commit Message
6562
run: |
66-
echo "COMMIT_MESSAGE=$(git show -s --format=%B)"
63+
gitTopLevel="$(git rev-parse --show-toplevel)"
64+
versionCodeFilter="\(versionCode\s\+=\s\+\)\([[:digit:]]\+\)"
65+
versionCode=$(git show "$tag:app/build.gradle.kts" | grep versionCode | sed -e "s/$versionCodeFilter/\2/" | xargs)
66+
67+
cat "$gitTopLevel/fastlane/metadata/android/en-US/changelogs/$versionCode.txt"
68+
6769
{
6870
echo 'COMMIT_MESSAGE<<EOF'
69-
git show -s --format=%B | sed -e 's/Change-Id:\s*\w\+//' | sed -e 's/Signed-off-by:\s*.*//' | sed ':a;N;$!ba;s/\n*$//'
71+
cat "$gitTopLevel/fastlane/metadata/android/en-US/changelogs/$versionCode.txt"
7072
echo EOF
7173
} >> $GITHUB_ENV
7274
7375
- name: Publish Release ${{ github.ref_name }}
74-
# noinspection SpellCheckingInspection
7576
uses: svenstaro/upload-release-action@v2
7677
with:
7778
file: ${{ env.ARTIFACT_PATH }}

app/build.gradle.kts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -115,8 +115,8 @@ android {
115115
minSdk = 24
116116
compileSdk = 35
117117
targetSdk = 35
118-
versionCode = 30
119-
versionName = "1.8.0"
118+
versionCode = 31
119+
versionName = "2.0.0"
120120

121121
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
122122

app/src/main/AndroidManifest.xml

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,11 @@
2424

2525
<activity
2626
android:name=".view.MainActivity"
27+
android:configChanges="screenSize|smallestScreenSize|screenLayout|orientation"
2728
android:exported="true"
28-
android:launchMode="singleTask">
29+
android:launchMode="singleTask"
30+
android:supportsPictureInPicture="true"
31+
android:resizeableActivity="true">
2932
<intent-filter>
3033
<action android:name="android.intent.action.MAIN" />
3134
<action android:name="android.service.quicksettings.action.QS_TILE_PREFERENCES" />

app/src/main/java/com/hifnawy/caffeinate/controller/ServiceStatus.kt

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ sealed class ServiceStatus {
3434
*
3535
* @author AbdAlMoniem AlHifnawy
3636
*/
37-
data class Running(private var startTimeout: Duration) : ServiceStatus() {
37+
class Running(startTimeout: Duration) : ServiceStatus() {
3838

3939
/**
4040
* Interface for observing changes to the remaining timeout duration while the service is running.
@@ -61,6 +61,16 @@ sealed class ServiceStatus {
6161
fun onRemainingUpdated()
6262
}
6363

64+
/**
65+
* The timeout duration in seconds.
66+
*
67+
* This property is used to determine when the service should stop.
68+
*
69+
* @return [Duration] the timeout duration in seconds.
70+
*/
71+
var startTimeout: Duration = startTimeout
72+
private set
73+
6474
/**
6575
* Indicates whether the service is running indefinitely.
6676
*

app/src/main/java/com/hifnawy/caffeinate/controller/SharedPrefsManager.kt

Lines changed: 31 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import com.hifnawy.caffeinate.controller.SharedPrefsManager.SharedPrefsKeys.CONT
1111
import com.hifnawy.caffeinate.controller.SharedPrefsManager.SharedPrefsKeys.ENABLE_DIMMING
1212
import com.hifnawy.caffeinate.controller.SharedPrefsManager.SharedPrefsKeys.ENABLE_MATERIAL_YOU
1313
import com.hifnawy.caffeinate.controller.SharedPrefsManager.SharedPrefsKeys.ENABLE_OVERLAY
14+
import com.hifnawy.caffeinate.controller.SharedPrefsManager.SharedPrefsKeys.ENABLE_PICTURE_IN_PICTURE
1415
import com.hifnawy.caffeinate.controller.SharedPrefsManager.SharedPrefsKeys.ENABLE_WHILE_LOCKED
1516
import com.hifnawy.caffeinate.controller.SharedPrefsManager.SharedPrefsKeys.IS_SERVICE_RUNNING
1617
import com.hifnawy.caffeinate.controller.SharedPrefsManager.SharedPrefsKeys.LAST_REMAINING_TIMEOUT
@@ -80,11 +81,6 @@ class SharedPrefsManager(private val caffeinateApplication: CaffeinateApplicatio
8081
*/
8182
CONTRAST_LEVEL,
8283

83-
/**
84-
* A [Boolean] value indicating whether the screen should be dimmed while the service is running.
85-
*/
86-
ENABLE_DIMMING,
87-
8884
/**
8985
* A [Boolean] value indicating whether Material You design elements should be enabled.
9086
*/
@@ -95,6 +91,16 @@ class SharedPrefsManager(private val caffeinateApplication: CaffeinateApplicatio
9591
*/
9692
ENABLE_OVERLAY,
9793

94+
/**
95+
* A [Boolean] value indicating whether the application should be enabled in picture-in-picture mode.
96+
*/
97+
ENABLE_PICTURE_IN_PICTURE,
98+
99+
/**
100+
* A [Boolean] value indicating whether the screen should be dimmed while the service is running.
101+
*/
102+
ENABLE_DIMMING,
103+
98104
/**
99105
* A [Boolean] value indicating whether the service should be enabled while the screen is locked.
100106
*/
@@ -222,24 +228,13 @@ class SharedPrefsManager(private val caffeinateApplication: CaffeinateApplicatio
222228
/**
223229
* List of available timeouts that can be selected by the user.
224230
*
225-
* This list is used to populate the [DialogChooseTimeoutsBinding][com.hifnawy.caffeinate.databinding.DialogChooseTimeoutsBinding] and provide the
226-
* user with a variety of timeouts to choose from.
227-
*
228-
* The items in this list are used to generate the list items in the
229-
* [DialogChooseTimeoutsBinding][com.hifnawy.caffeinate.databinding.DialogChooseTimeoutsBinding] and are used to populate the
230-
* [CheckBoxItem] list.
231-
*
232231
* @return [List] A list of [Duration] objects representing the available timeouts.
233232
*/
234233
// val timeouts by lazy { listOf(30.seconds, 5.minutes, 10.minutes, 15.minutes, 30.minutes, 60.minutes, 120.minutes, 240.minutes, 480.minutes, Duration.INFINITE) }
235234
val timeouts by lazy { listOf(30.seconds, 5.minutes, 10.minutes, 15.minutes, 30.minutes, 60.minutes, Duration.INFINITE) }
236235

237236
/**
238-
* Checks if all necessary permissions are granted.
239-
*
240-
* This property is used to keep track of whether all necessary permissions have been granted. It is used to determine whether the main activity
241-
* should display the [DialogChooseTimeoutsBinding][com.hifnawy.caffeinate.databinding.DialogChooseTimeoutsBinding] or not, and to enable or
242-
* disable the [DialogChooseTimeoutsBinding][com.hifnawy.caffeinate.databinding.DialogChooseTimeoutsBinding] based on the state of this property.
237+
* Retrieves or sets whether all necessary permissions are granted.
243238
*
244239
* @return [Boolean] `true` if all necessary permissions are granted, `false` otherwise.
245240
*/
@@ -305,6 +300,18 @@ class SharedPrefsManager(private val caffeinateApplication: CaffeinateApplicatio
305300
notifySharedPrefsObservers { observer -> observer.onIsOverlayEnabledUpdated(value) }
306301
}
307302

303+
/**
304+
* Retrieves or sets whether picture-in-picture mode is enabled.
305+
*
306+
* This property is used to get or update the preference of whether picture-in-picture mode should be enabled.
307+
* It allows the application to persist the user's preference across sessions.
308+
*
309+
* @return [Boolean] `true` if picture-in-picture mode is enabled, `false` otherwise.
310+
*/
311+
var isPictureInPictureEnabled: Boolean
312+
get() = sharedPreferences.getBoolean(ENABLE_PICTURE_IN_PICTURE.name, false)
313+
set(value) = sharedPreferences.edit().putBoolean(ENABLE_PICTURE_IN_PICTURE.name, value).apply()
314+
308315
/**
309316
* Retrieves or sets whether the screen should be dimmed while it is being kept awake.
310317
*
@@ -458,6 +465,13 @@ interface SharedPrefsObserver : Observer {
458465
*/
459466
fun onIsOverlayEnabledUpdated(isOverlayEnabled: Boolean) = Unit
460467

468+
/**
469+
* Called when the "Picture in Picture Enabled" preference changes.
470+
*
471+
* @param isPictureInPictureEnabled [Boolean] `true` if the "Picture in Picture" feature is enabled, `false` otherwise.
472+
*/
473+
fun onIsPictureInPictureEnabledUpdated(isPictureInPictureEnabled: Boolean) = Unit
474+
461475
/**
462476
* Called when the "Dimming Enabled" preference changes.
463477
*

app/src/main/java/com/hifnawy/caffeinate/utils/ViewExtensionFunctions.kt

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package com.hifnawy.caffeinate.utils
22

3+
import android.graphics.Rect
34
import android.view.View
45

56
/**
@@ -25,4 +26,24 @@ object ViewExtensionFunctions {
2526
set(value) {
2627
visibility = if (value) View.VISIBLE else View.GONE
2728
}
29+
30+
/**
31+
* Sets a listener to be called when the size of the view changes.
32+
*
33+
* This extension function adds an OnLayoutChangeListener to the view which executes the provided
34+
* callback whenever the view's size changes. The callback provides the new and old dimensions of
35+
* the view, allowing developers to respond to size changes.
36+
*
37+
* @param callback A function to be invoked when the view's size changes. It receives the view itself,
38+
* the new width and height, and the old width and height as parameters.
39+
*/
40+
inline fun View.onSizeChange(crossinline callback: (view: View, newWidth: Int, newHeight: Int, oldWidth: Int, oldHeight: Int) -> Unit) =
41+
addOnLayoutChangeListener { view, left, top, right, bottom, oldLeft, oldTop, oldRight, oldBottom ->
42+
val rect = Rect(left, top, right, bottom)
43+
val oldRect = Rect(oldLeft, oldTop, oldRight, oldBottom)
44+
45+
if (rect.width() == oldRect.width() && rect.height() == oldRect.height()) return@addOnLayoutChangeListener
46+
47+
callback(view, rect.width(), rect.height(), oldRect.width(), oldRect.height())
48+
}
2849
}

0 commit comments

Comments
 (0)