Skip to content

Commit

Permalink
Android review (bluecherrydvr#166)
Browse files Browse the repository at this point in the history
  • Loading branch information
bdlukaa authored Oct 23, 2023
2 parents fbc5cfb + 2ed3583 commit 89b26d5
Show file tree
Hide file tree
Showing 30 changed files with 613 additions and 631 deletions.
6 changes: 4 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,8 @@ Let's say, we're adding French (`fr`) translation.
3. Add your translations to your new `app_fr.arb` file in correspondence to existing [English translations](https://github.com/bluecherrydvr/unity/tree/main/lib/l10n/app_en.arb).
4. Send us a new pull-request. 🎉

When adding new strings, run `bin/l10n_organizer.dart`. This script will ensure that the new strings are added to all l10n files and that they are in the same location. It will also remove any unused strings. The base file is `app_en.arb`, so all strings must be added there first.

## Bug-Reports

Send us details about any issues you discover [in the issues](https://github.com/bluecherrydvr/unity/issues) or [in the forums](https://forums.bluecherrydvr.com/).
Expand Down Expand Up @@ -120,7 +122,7 @@ lib
│ ├───mobile_view_provider.dart [stores, provides & caches mobile camera layout etc.]
│ ├───server_provider.dart [stores, provides & caches multiple DVR servers added by the user.]
│ └───settings_provider.dart [stores, provides & caches various in-app configurations & settings.]
│ └───update_provider.dart [manages app updates and app status.]
│ └───update_provider.dart [manages app updates and app status.]
├───utils [constant values, helper functions & theme-related stuff.]
│ ├───constants.dart
Expand Down Expand Up @@ -155,7 +157,7 @@ flutter build [linux|windows|android|ios]

The automated build process is done using GitHub Actions. You may find the workflow [here](.github/workflows/main.yml). The workflow builds the app for all supported platforms & uploads the artifacts to the release page.

On Linux, a Flutter executable with different environment variables is used to build the app for different distributions. This tells the app how the system is configured and how it should install updates. To run for Linux, you need to provide the following environment variables based on your system, where `[DISTRO_ENV]` can be `appimage`, `deb`, `rpm` or `tar.gz` (Tarball).
On Linux, a Flutter executable with different environment variables is used to build the app for different distributions. This tells the app how the system is configured and how it should install updates. To run for Linux, you need to provide the following environment variables based on your system, where `[DISTRO_ENV]` can be `appimage` (AppImage), `deb` (Debian), `rpm` (RedHat) or `tar.gz` (Tarball).

```bash
flutter run --dart-define-from-file=linux/env/[DISTRO_ENV].json
Expand Down
2 changes: 1 addition & 1 deletion android/app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ apply plugin: 'kotlin-android'
apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle"

android {
compileSdkVersion 33
compileSdkVersion 34
ndkVersion flutter.ndkVersion

compileOptions {
Expand Down
2 changes: 2 additions & 0 deletions lib/l10n/app_en.arb
Original file line number Diff line number Diff line change
Expand Up @@ -386,6 +386,8 @@
"@@MISC": {},
"general": "General",
"miscellaneous": "Miscellaneous",
"wakelock": "Keep screen on",
"wakelockDescription": "Keep screen on while watching live streams or recordings.",
"@Snoozing": {},
"snooze15": "15 minutes",
"snooze30": "30 minutes",
Expand Down
2 changes: 2 additions & 0 deletions lib/l10n/app_fr.arb
Original file line number Diff line number Diff line change
Expand Up @@ -362,6 +362,8 @@
"@@MISC": {},
"general": "General",
"miscellaneous": "Divers",
"wakelock": "Keep screen on",
"wakelockDescription": "Keep screen on while watching live streams or recordings.",
"@Snoozing": {},
"snooze15": "15 minutes",
"snooze30": "30 minutes",
Expand Down
2 changes: 2 additions & 0 deletions lib/l10n/app_pl.arb
Original file line number Diff line number Diff line change
Expand Up @@ -386,6 +386,8 @@
"@@MISC": {},
"general": "General",
"miscellaneous": "Różne",
"wakelock": "Keep screen on",
"wakelockDescription": "Keep screen on while watching live streams or recordings.",
"@Snoozing": {},
"snooze15": "15 minut",
"snooze30": "30 minut",
Expand Down
2 changes: 2 additions & 0 deletions lib/l10n/app_pt.arb
Original file line number Diff line number Diff line change
Expand Up @@ -386,6 +386,8 @@
"@@MISC": {},
"general": "Geral",
"miscellaneous": "Outros",
"wakelock": "Deixar tela ligada",
"wakelockDescription": "Mantenha a tela ligada enquanto estiver assistindo a streams ao vivo ou gravações",
"@Snoozing": {},
"snooze15": "15 minutos",
"snooze30": "30 minutos",
Expand Down
2 changes: 1 addition & 1 deletion lib/providers/desktop_view_provider.dart
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@ class DesktopViewProvider extends ChangeNotifier {

/// Releases a device if no layout is using it
void _releaseDevice(Device device) {
if (!UnityPlayers.players.containsKey(device)) return;
if (!UnityPlayers.players.containsKey(device.uuid)) return;
if (!layouts
.any((layout) => layout.devices.any((d) => d.id == device.id))) {
UnityPlayers.releaseDevice(device.uuid);
Expand Down
25 changes: 24 additions & 1 deletion lib/providers/home_provider.dart
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,13 @@

import 'package:bluecherry_client/main.dart';
import 'package:bluecherry_client/providers/server_provider.dart';
import 'package:bluecherry_client/providers/settings_provider.dart';
import 'package:bluecherry_client/utils/methods.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:provider/provider.dart';
import 'package:wakelock_plus/wakelock_plus.dart';

enum UnityTab {
deviceGrid,
Expand Down Expand Up @@ -85,8 +87,9 @@ class HomeProvider extends ChangeNotifier {
automaticallyGoToAddServersScreen = false;
}

notifyListeners();
refreshDeviceOrientation(context);
updateWakelock(context);
notifyListeners();
}

bool automaticallyGoToAddServersScreen = false;
Expand Down Expand Up @@ -115,6 +118,8 @@ class HomeProvider extends ChangeNotifier {

Future<void> refreshDeviceOrientation(BuildContext context) async {
if (isMobile) {
if (Navigator.of(context).canPop()) return;

final home = context.read<HomeProvider>();
final tab = home.tab;

Expand All @@ -136,6 +141,24 @@ class HomeProvider extends ChangeNotifier {
}
}

void updateWakelock(BuildContext context) {
final settings = context.read<SettingsProvider>();

if (!settings.wakelockEnabled) {
WakelockPlus.disable();
} else {
switch (tab) {
case UnityTab.deviceGrid:
case UnityTab.eventsPlayback:
WakelockPlus.enable();
break;
default:
WakelockPlus.disable();
break;
}
}
}

/// Whether something in the app is loading
bool get isLoading => loadReasons.isNotEmpty;
void loading(UnityLoadingReason reason, {bool notify = true}) {
Expand Down
135 changes: 54 additions & 81 deletions lib/providers/settings_provider.dart
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,6 @@ import 'package:unity_video_player/unity_video_player.dart';

/// This class manages & saves the settings inside the application.
class SettingsProvider extends ChangeNotifier {
/// `late` initialized [SettingsProvider] instance.
static late final SettingsProvider instance;

static const kDefaultThemeMode = ThemeMode.system;
Expand All @@ -50,6 +49,22 @@ class SettingsProvider extends ChangeNotifier {
static const kDefaultStreamingType = StreamingType.rtsp;
static const kDefaultRTSPProtocol = RTSPProtocol.tcp;
static const kDefaultVideoQuality = RenderingQuality.automatic;
static const kDefaultWakelockEnabled = true;

late Locale _locale;
late ThemeMode _themeMode;
late DateFormat _dateFormat;
late DateFormat _timeFormat;
late DateTime _snoozedUntil;
late NotificationClickBehavior _notificationClickBehavior;
late UnityVideoFit _cameraViewFit;
late String _downloadsDirectory;
late bool _layoutCyclingEnabled;
late Duration _layoutCyclingTogglePeriod;
late StreamingType _streamingType;
late RTSPProtocol _rtspProtocol;
late RenderingQuality _videoQuality;
late bool _wakelockEnabled;

// Getters.
Locale get locale => _locale;
Expand All @@ -66,6 +81,7 @@ class SettingsProvider extends ChangeNotifier {
StreamingType get streamingType => _streamingType;
RTSPProtocol get rtspProtocol => _rtspProtocol;
RenderingQuality get videoQuality => _videoQuality;
bool get wakelockEnabled => _wakelockEnabled;

// Setters.
set locale(Locale value) {
Expand Down Expand Up @@ -142,19 +158,11 @@ class SettingsProvider extends ChangeNotifier {
_save();
}

late Locale _locale;
late ThemeMode _themeMode;
late DateFormat _dateFormat;
late DateFormat _timeFormat;
late DateTime _snoozedUntil;
late NotificationClickBehavior _notificationClickBehavior;
late UnityVideoFit _cameraViewFit;
late String _downloadsDirectory;
late bool _layoutCyclingEnabled;
late Duration _layoutCyclingTogglePeriod;
late StreamingType _streamingType;
late RTSPProtocol _rtspProtocol;
late RenderingQuality _videoQuality;
set wakelockEnabled(bool value) {
_wakelockEnabled = value;
UnityVideoPlayerInterface.wakelockEnabled = value;
_save();
}

/// Initializes the [SettingsProvider] instance & fetches state from `async`
/// `package:hive` method-calls. Called before [runApp].
Expand Down Expand Up @@ -185,6 +193,7 @@ class SettingsProvider extends ChangeNotifier {
kHiveStreamingType: streamingType.index,
kHiveStreamingProtocol: rtspProtocol.index,
kHiveVideoQuality: videoQuality.index,
kWakelockEnabled: wakelockEnabled,
});

if (notify) notifyListeners();
Expand Down Expand Up @@ -215,72 +224,36 @@ class SettingsProvider extends ChangeNotifier {

final systemLocale = Intl.getCurrentLocale();
final timePattern = await format.getTimePattern();
if (data.containsKey(kHiveDateFormat)) {
_dateFormat = DateFormat(data[kHiveDateFormat]!, systemLocale);
} else {
_dateFormat = DateFormat(kDefaultDateFormat, systemLocale);
}
if (data.containsKey(kHiveTimeFormat)) {
_timeFormat = DateFormat(data[kHiveTimeFormat]!, systemLocale);
} else {
_timeFormat = DateFormat(timePattern ?? kDefaultTimeFormat, systemLocale);
}
if (data.containsKey(kHiveSnoozedUntil)) {
_snoozedUntil = DateTime.parse(
data[kHiveSnoozedUntil]!,
);
} else {
_snoozedUntil = defaultSnoozedUntil;
}
if (data.containsKey(kHiveNotificationClickBehavior)) {
_notificationClickBehavior = NotificationClickBehavior
.values[data[kHiveNotificationClickBehavior]!];
} else {
_notificationClickBehavior = kDefaultNotificationClickBehavior;
}
if (data.containsKey(kHiveCameraViewFit)) {
_cameraViewFit = UnityVideoFit.values[data[kHiveCameraViewFit]!];
} else {
_cameraViewFit = kDefaultCameraViewFit;
}

if (data.containsKey(kHiveDownloadsDirectorySetting)) {
_downloadsDirectory = data[kHiveDownloadsDirectorySetting];
} else {
_downloadsDirectory = (await kDefaultDownloadsDirectory).path;
}

if (data.containsKey(kHiveLayoutCycling)) {
_layoutCyclingEnabled = data[kHiveLayoutCycling];
} else {
_layoutCyclingEnabled = kDefaultLayoutCyclingEnabled;
}

if (data.containsKey(kHiveLayoutCyclingPeriod)) {
_layoutCyclingTogglePeriod = Duration(
milliseconds: data[kHiveLayoutCyclingPeriod],
);
} else {
_layoutCyclingTogglePeriod = kDefaultLayoutCyclingTogglePeriod;
}

if (data.containsKey(kHiveStreamingType)) {
_streamingType = StreamingType.values[data[kHiveStreamingType]!];
} else {
_streamingType = kDefaultStreamingType;
}

if (data.containsKey(kHiveStreamingProtocol)) {
_rtspProtocol = RTSPProtocol.values[data[kHiveStreamingProtocol]!];
} else {
_rtspProtocol = kDefaultRTSPProtocol;
}

if (data.containsKey(kHiveVideoQuality)) {
_videoQuality = RenderingQuality.values[data[kHiveVideoQuality]!];
} else {
_videoQuality = kDefaultVideoQuality;
}
_dateFormat = DateFormat(
data[kHiveDateFormat] ?? kDefaultDateFormat,
systemLocale,
);
_timeFormat = DateFormat(
data[kHiveTimeFormat] ?? timePattern ?? kDefaultTimeFormat,
systemLocale,
);
_snoozedUntil =
DateTime.tryParse(data[kHiveSnoozedUntil]) ?? defaultSnoozedUntil;
_notificationClickBehavior = NotificationClickBehavior.values[
data[kHiveNotificationClickBehavior] ??
kDefaultNotificationClickBehavior.index];
_cameraViewFit = UnityVideoFit
.values[data[kHiveCameraViewFit] ?? kDefaultCameraViewFit.index];
_downloadsDirectory = data[kHiveDownloadsDirectorySetting] ??
((await kDefaultDownloadsDirectory).path);
_layoutCyclingEnabled =
data[kHiveLayoutCycling] ?? kDefaultLayoutCyclingEnabled;
_layoutCyclingTogglePeriod = Duration(
milliseconds: data[kHiveLayoutCyclingPeriod] ??
kDefaultLayoutCyclingTogglePeriod.inMilliseconds,
);
_streamingType = StreamingType
.values[data[kHiveStreamingType] ?? kDefaultStreamingType.index];
_rtspProtocol = RTSPProtocol
.values[data[kHiveStreamingProtocol] ?? kDefaultRTSPProtocol.index];
_videoQuality = RenderingQuality
.values[data[kHiveVideoQuality] ?? kDefaultVideoQuality.index];
_wakelockEnabled = data[kWakelockEnabled] ?? kDefaultWakelockEnabled;

notifyListeners();
}
Expand Down Expand Up @@ -355,5 +328,5 @@ enum RenderingQuality {
enum StreamingType {
rtsp,
hls,
mjpeg,
mjpeg;
}
1 change: 1 addition & 0 deletions lib/utils/constants.dart
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ const kHiveLastCheck = 'last_update_check';
const kHiveStreamingType = 'streaming_type';
const kHiveStreamingProtocol = 'streaming_protocol';
const kHiveVideoQuality = 'video_quality';
const kWakelockEnabled = 'wakelock_enabled';

/// Used as frame buffer size in [DeviceTile], and calculating aspect ratio. Only relevant on desktop.
const kDeviceTileWidth = 640.0;
Expand Down
34 changes: 34 additions & 0 deletions lib/utils/storage.dart
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

import 'dart:io';

import 'package:bluecherry_client/utils/constants.dart';
import 'package:flutter/foundation.dart';
import 'package:hive_flutter/hive_flutter.dart';
Expand Down Expand Up @@ -106,3 +108,35 @@ extension SafeLocalStorageExtension on SafeLocalStorage {
return Future.value();
}
}

enum LogType { video, network }

Future<Directory> errorLogDirectory() async {
final documentsDir = await getApplicationDocumentsDirectory();
final logsDir = Directory(path.join(documentsDir.path, 'logs'));
await logsDir.create(recursive: true);
return logsDir;
}

Future<File> errorLogFile(LogType type) {
return errorLogDirectory().then<File>((dir) async {
final now = DateTime.now();
final today = DateTime(now.year, now.month, now.day);
final filename = '${today.toIso8601String()}.log';
final file = File(path.join(dir.path, type.name, filename));
await file.create(recursive: true);
return file;
});
}

Future<File> errorLog(LogType type, String message) async {
final file = await errorLogFile(type);

final now = DateTime.now();
final timestamp = now.toIso8601String();
final log = '$timestamp: $message\n';

await file.writeAsString(log, mode: FileMode.append);

return file;
}
2 changes: 1 addition & 1 deletion lib/utils/widgets/tree_view.dart
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,7 @@ List<TreeNode>? _copyNodesRecursively(
}

class _TreeNodeKey extends ValueKey {
const _TreeNodeKey(dynamic value) : super(value);
const _TreeNodeKey(super.value);
}

/// Provides unique keys and verifies duplicates.
Expand Down
2 changes: 1 addition & 1 deletion lib/widgets/device_grid/mobile/device_view.dart
Original file line number Diff line number Diff line change
Expand Up @@ -256,7 +256,7 @@ class DeviceTileState extends State<DeviceTile> {
const Center(
child: CircularProgressIndicator.adaptive(
valueColor: AlwaysStoppedAnimation(Colors.white),
strokeWidth: 4.4,
strokeWidth: 1.5,
),
),
if (video.lastImageUpdate != null)
Expand Down
Loading

0 comments on commit 89b26d5

Please sign in to comment.