Skip to content

Commit 625f73b

Browse files
authored
Merge pull request #86 from lbr38/devel
6.0.0
2 parents 37ffe15 + 3a4713c commit 625f73b

File tree

145 files changed

+11681
-2381
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

145 files changed

+11681
-2381
lines changed

.github/workflows/build-image.yml

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,11 @@ jobs:
4343
with:
4444
file: ./docker/Dockerfile
4545
# Debug only
46-
# push: false
46+
# push: true
47+
# tags: lbr38/motionui:${{ env.VERSION }}-test
48+
# platforms: linux/amd64,linux/i386,linux/arm/v7,linux/arm64
49+
50+
# Production
4751
push: true
4852
tags: lbr38/motionui:latest, lbr38/motionui:${{ env.VERSION }}
4953
platforms: linux/amd64,linux/i386,linux/arm/v7,linux/arm64

.github/workflows/phpcs.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,4 +26,4 @@ jobs:
2626
php phpcs.phar --version
2727
2828
- name: Detect coding standard violations
29-
run: php phpcs.phar --standard=$GITHUB_WORKSPACE/lint/phpcs.xml --colors -n $GITHUB_WORKSPACE --ignore=libs/
29+
run: php phpcs.phar --standard=$GITHUB_WORKSPACE/lint/phpcs.xml --colors -n $GITHUB_WORKSPACE --ignore=libs/,public/resources/js/webrtc/
Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,136 @@
1+
name: Database update tests
2+
3+
on:
4+
push:
5+
branches: [ devel ]
6+
pull_request:
7+
push:
8+
branches: [ main ]
9+
jobs:
10+
test-database-update:
11+
runs-on: ubuntu-latest
12+
steps:
13+
- name: Checkout
14+
uses: actions/checkout@v4
15+
16+
- name: Install docker-compose
17+
run: |
18+
sudo apt-get update
19+
sudo apt-get install -y docker-compose
20+
21+
# Get all releases
22+
# Format them to a key-value array
23+
# Start from release index 5.0.0
24+
# Pull images starting from release 5.0.0
25+
# Ignore releases which contain "android"
26+
# Then pull the next image of the index, etc..
27+
- name: Test all releases update from lbr38/motionui
28+
run: |
29+
RELEASES=$(curl -s https://api.github.com/repos/lbr38/motion-ui/releases?per_page=10000 | jq -r '.[].name' | tac)
30+
31+
index="0"
32+
declare -A RELEASES_ARRAY
33+
for release in $RELEASES; do
34+
RELEASES_ARRAY["$index"]="$release"
35+
index=$((index+1))
36+
done
37+
38+
for i in "${!RELEASES_ARRAY[@]}"; do
39+
if [[ "${RELEASES_ARRAY[$i]}" == "5.0.0" ]]; then
40+
start_index="$i"
41+
break
42+
fi
43+
done
44+
45+
for ((i=start_index; i<${#RELEASES_ARRAY[@]}; i++)); do
46+
release="${RELEASES_ARRAY[$i]}"
47+
48+
if [[ "$release" == *"android"* ]]; then
49+
continue
50+
fi
51+
52+
docker rm -f motionui
53+
docker system prune -a -f
54+
55+
echo -e "\nPulling image for release $release\n"
56+
57+
docker run -d --restart always --name motionui \
58+
-e FQDN=motionui.test.com \
59+
-p 8080:8080 \
60+
-p 8555:8555 \
61+
-v /etc/localtime:/etc/localtime:ro \
62+
-v /var/lib/docker/volumes/motionui-data:/var/lib/motionui \
63+
-v /var/lib/docker/volumes/motionui-captures:/var/lib/motion \
64+
lbr38/motionui:$release
65+
66+
if [ $? -ne 0 ]; then
67+
echo "Failed to pull image for release $release"
68+
exit 1
69+
fi
70+
71+
echo -e "\nNow checking for errors in container logs\n"
72+
73+
# Wait 20sec for the container to start
74+
sleep 20
75+
76+
# Retrieve and check errors in container logs
77+
OUTPUT=$(docker logs motionui -n10000)
78+
79+
# Check if the logs contains error or failed message
80+
if echo "$OUTPUT" | grep -q -i -E "error|failed|unknown|uncaught|warning"; then
81+
echo "Database update seems to have failed: $OUTPUT"
82+
exit 1
83+
fi
84+
85+
# Quit the loop if the maintenance page is disabled (meaning the update is done) => no maintenance page in oldest releases, looping forever
86+
#if echo "$OUTPUT" | grep -q "Disabling maintenance page"; then
87+
# break
88+
#fi
89+
done
90+
91+
# Finally, test the devel image
92+
- name: Test devel image from lbr38/motionui
93+
run: |
94+
docker rm -f motionui
95+
docker system prune -a -f
96+
97+
echo -e "\Build devel image\n"
98+
99+
cd ${GITHUB_WORKSPACE}/docker
100+
101+
sed -i 's/env:.*/env: devel/g' docker-compose.yml
102+
sed -i 's/fqdn:.*/fqdn: motionui.test.com/g' docker-compose.yml
103+
104+
docker-compose -f docker-compose.yml up -d
105+
106+
if [ $? -ne 0 ]; then
107+
echo "Failed to build devel image"
108+
exit 1
109+
fi
110+
111+
# Retrieve and check errors in container logs
112+
while true; do
113+
OUTPUT=$(docker logs motionui -n10000)
114+
115+
# Check if the logs contains failed message
116+
if echo "$OUTPUT" | grep -q -i "failed"; then
117+
echo "Database update seems to have failed: $OUTPUT"
118+
exit 1
119+
fi
120+
121+
# Check if the logs contains error message
122+
if echo "$OUTPUT" | grep -q -i "error"; then
123+
echo "Database update seems to have failed: $OUTPUT"
124+
exit 1
125+
fi
126+
127+
# Quit the loop if the maintenance page is disabled (meaning the update is done)
128+
if echo "$OUTPUT" | grep -q "Disabling maintenance page"; then
129+
break
130+
fi
131+
132+
sleep 2
133+
done
134+
135+
# Print final container logs output
136+
echo "$OUTPUT"

README.md

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -22,12 +22,12 @@ A dockerized web responsive interface to manage <a href="https://github.com/Moti
2222

2323
## 🚀 Features
2424

25-
- Visualize camera stream.
26-
- Start and stop motion detection from the web interface.
25+
- Visualize cameras stream (sound supported).
26+
- Record motion detection (sound supported).
2727
- Enable **autostart and stop** of the motion detection, based on time slots or on device presence on the local network. If none of the known devices are connected to the local network then motion detection will be automatically started as nobody is at home.
2828
- Receive email alerts on motion detection.
29-
- Visualize captured images and videos and/or download them.
30-
- Create timelapses.
29+
- Visualize recorded images and videos and download them.
30+
- Record timelapses.
3131

3232
## 📷 Supported cameras
3333

@@ -39,7 +39,7 @@ A dockerized web responsive interface to manage <a href="https://github.com/Moti
3939

4040
### Hardware
4141

42-
- CPU and RAM can be very sollicitated when motion service is running depending on the number of cameras and the resolution of the stream.
42+
- CPU and RAM can be very sollicitated when motion detection is running depending on the number of cameras and the resolution of the stream.
4343
- Disk space depends on the number of cameras and the number of days you want to keep images and videos.
4444

4545
### Software and configuration

android/motionUI/app/src/main/AndroidManifest.xml

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,13 +30,14 @@
3030
android:exported="true">
3131
<intent-filter>
3232
<action android:name="android.intent.action.MAIN" />
33-
3433
<category android:name="android.intent.category.LAUNCHER" />
3534
</intent-filter>
3635
</activity>
3736
<activity
3837
android:name="app.motionui.android.MainActivity"
39-
android:exported="true"></activity>
38+
android:exported="true"
39+
android:configChanges="orientation|screenSize|keyboardHidden">
40+
</activity>
4041
</application>
4142

4243
</manifest>
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
package app.motionui.android;
2+
3+
import android.view.View;
4+
import android.webkit.WebChromeClient;
5+
import android.webkit.WebView;
6+
import android.widget.FrameLayout;
7+
import androidx.appcompat.app.AppCompatActivity;
8+
9+
public class FullScreenWebChromeClient extends WebChromeClient {
10+
private AppCompatActivity activity;
11+
private View customView;
12+
private FrameLayout customViewContainer;
13+
private CustomViewCallback customViewCallback;
14+
private WebView webView;
15+
16+
public FullScreenWebChromeClient(AppCompatActivity activity, WebView webView) {
17+
this.activity = activity;
18+
this.webView = webView;
19+
this.customViewContainer = activity.findViewById(R.id.fullscreen_container);
20+
}
21+
22+
@Override
23+
public void onShowCustomView(View view, CustomViewCallback callback) {
24+
if (customView != null) {
25+
callback.onCustomViewHidden();
26+
return;
27+
}
28+
29+
// Add the custom view for full screen
30+
customViewContainer.addView(view, FrameLayout.LayoutParams.MATCH_PARENT);
31+
customViewContainer.setVisibility(View.VISIBLE);
32+
customView = view;
33+
customViewCallback = callback;
34+
35+
// Hide the main WebView
36+
webView.setVisibility(View.GONE);
37+
38+
activity.getWindow().getDecorView().setSystemUiVisibility(
39+
View.SYSTEM_UI_FLAG_FULLSCREEN |
40+
View.SYSTEM_UI_FLAG_HIDE_NAVIGATION |
41+
View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY
42+
);
43+
44+
if (activity instanceof MainActivity) {
45+
((MainActivity) activity).setFullScreen(true);
46+
}
47+
}
48+
49+
@Override
50+
public void onHideCustomView() {
51+
if (customView == null) {
52+
return;
53+
}
54+
55+
// Remove the custom view and restore the main WebView
56+
customViewContainer.removeView(customView);
57+
customViewContainer.setVisibility(View.GONE);
58+
customView = null;
59+
customViewCallback.onCustomViewHidden();
60+
61+
webView.setVisibility(View.VISIBLE);
62+
63+
activity.getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_VISIBLE);
64+
65+
if (activity instanceof MainActivity) {
66+
((MainActivity) activity).setFullScreen(false);
67+
}
68+
}
69+
}

android/motionUI/app/src/main/java/app/motionui/android/MainActivity.java

Lines changed: 33 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,12 @@
44
import android.widget.Toast;
55
import android.app.DownloadManager;
66
import android.content.Intent;
7+
import android.content.pm.PackageManager;
8+
import android.content.res.Configuration;
79
import android.net.Uri;
810
import android.os.Environment;
911
import android.os.Bundle;
12+
import android.os.Build;
1013
import android.util.Log;
1114
import android.view.KeyEvent;
1215
import android.webkit.DownloadListener;
@@ -15,10 +18,8 @@
1518
import android.webkit.WebResourceRequest;
1619
import android.webkit.WebView;
1720
import android.webkit.WebViewClient;
18-
import android.os.Build;
1921
import android.webkit.CookieManager;
2022
import android.Manifest;
21-
import android.content.pm.PackageManager;
2223
import androidx.core.app.ActivityCompat;
2324
import androidx.core.content.ContextCompat;
2425
import androidx.annotation.NonNull;
@@ -31,6 +32,7 @@ public class MainActivity extends AppCompatActivity {
3132
private static final int STORAGE_PERMISSION_REQUEST_CODE = 1001;
3233
private WebView webView;
3334
private String url;
35+
private boolean isFullScreen = false;
3436
// private Integer authTry = 0;
3537

3638
/**
@@ -97,8 +99,10 @@ protected void onCreate(Bundle savedInstanceState) {
9799
webView.getSettings().setBuiltInZoomControls(true);
98100
webView.getSettings().setDisplayZoomControls(false);
99101

100-
// For debugging:
101-
webView.setWebChromeClient(new WebChromeClient());
102+
/**
103+
* Use custom WebChromeClient to enable features like full-screen video
104+
*/
105+
webView.setWebChromeClient(new FullScreenWebChromeClient(this, webView));
102106

103107
/**
104108
* Enable JavaScript interface "MyJavaScriptInterface()" to retrieve username and password from the login form when the user submits it and save them in SharedPreferences
@@ -247,8 +251,16 @@ public void onDownloadStart(String url, String userAgent, String contentDisposit
247251

248252
/**
249253
* Load motionUI URL in the WebView
254+
* Restore webview state if it was saved (e.g. when the device is rotated)
255+
* Otherwise, load the URL
250256
*/
251-
webView.loadUrl(url);
257+
if (savedInstanceState != null) {
258+
webView.restoreState(savedInstanceState);
259+
isFullScreen = savedInstanceState.getBoolean("isFullScreen", false);
260+
} else {
261+
// Load the URL
262+
webView.loadUrl(url);
263+
}
252264
}
253265

254266
/**
@@ -265,6 +277,22 @@ public boolean onKeyDown(int keyCode, KeyEvent event) {
265277
return super.onKeyDown(keyCode, event);
266278
}
267279

280+
@Override
281+
protected void onSaveInstanceState(@NonNull Bundle outState) {
282+
super.onSaveInstanceState(outState);
283+
webView.saveState(outState);
284+
outState.putBoolean("isFullScreen", isFullScreen);
285+
}
286+
287+
@Override
288+
public void onConfigurationChanged(@NonNull Configuration newConfig) {
289+
super.onConfigurationChanged(newConfig);
290+
}
291+
292+
public void setFullScreen(boolean isFullScreen) {
293+
this.isFullScreen = isFullScreen;
294+
}
295+
268296
/**
269297
* Check that the app has the necessary permissions to access the storage
270298
*/
Loading

android/motionUI/app/src/main/res/layout/activity_main.xml

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,4 +14,14 @@
1414
app:layout_constraintEnd_toEndOf="parent"
1515
app:layout_constraintStart_toStartOf="parent"
1616
app:layout_constraintTop_toTopOf="parent" />
17+
18+
<FrameLayout
19+
android:id="@+id/fullscreen_container"
20+
android:layout_width="match_parent"
21+
android:layout_height="match_parent"
22+
android:visibility="gone"
23+
app:layout_constraintBottom_toBottomOf="parent"
24+
app:layout_constraintEnd_toEndOf="parent"
25+
app:layout_constraintStart_toStartOf="parent"
26+
app:layout_constraintTop_toTopOf="parent" />
1727
</androidx.constraintlayout.widget.ConstraintLayout>
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
<?xml version="1.0" encoding="utf-8"?>
22
<resources>
3-
<color name="ic_launcher_background">#112334</color>
3+
<color name="ic_launcher_background">#102232</color>
44
</resources>

0 commit comments

Comments
 (0)