Skip to content

Commit

Permalink
Set volume to value between 0 and 1 (#98)
Browse files Browse the repository at this point in the history
* Set volume property as double

* Update volume value to iOS and Android methods

* Add volume slider in example app

* Fix iOS volume argument name

* Fix iOS build errors

* Fix iOS volume type error

* Update changelog + add minor adjustments
  • Loading branch information
gdelataillade committed Nov 18, 2023
1 parent 5e01be2 commit 7709568
Show file tree
Hide file tree
Showing 11 changed files with 109 additions and 66 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
* Remove [stopOnNotificationOpen] property.
* Make notification mandatory so android foreground services can be used.
* [Android] Refactor alarm to native android services.
* Replace [volumeMax] with [volume] double property.

## 2.2.0
* [Android] Move alarm service to native code.
Expand Down
21 changes: 11 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ final alarmSettings = AlarmSettings(
assetAudioPath: 'assets/alarm.mp3',
loopAudio: true,
vibrate: true,
volumeMax: true,
volume: 0.8,
fadeDuration: 3.0,
notificationTitle: 'This is the title',
notificationBody: 'This is the body',
Expand All @@ -58,7 +58,8 @@ alarmDateTime | `DateTime` | The date and time you want your alarm to ring
assetAudio | `String` | The path to you audio asset you want to use as ringtone. Can be a path in your assets folder or a downloaded local file path.
loopAudio | `bool` | If true, audio will repeat indefinitely until alarm is stopped.
vibrate | `bool` | If true, device will vibrate indefinitely until alarm is stopped. If [loopAudio] is set to false, vibrations will stop when audio ends.
volumeMax | `bool` | If true, set system volume to maximum when [dateTime] is reached. Set back to previous volume when alarm is stopped.
volume | `double` | Sets system volume level (0 to 1) at [dateTime]; reverts on alarm stop. Defaults to current volume if null.
when alarm is stopped.
fadeDuration | `double` | Duration, in seconds, over which to fade the alarm volume. Set to 0 by default, which means no fade.
notificationTitle | `String` | The title of the notification triggered when alarm rings if app is on background.
notificationBody | `String` | The body of the notification.
Expand Down Expand Up @@ -91,14 +92,14 @@ Don't hesitate to check out the example's code, and take a look at the app:

## ⏰ Alarm behaviour

| | Sound | Vibrate | Volume max | Notification
| ------------------------ | ----- | ------- | ---------- | -------
| Locked screen | ✅ | ✅ | ✅ | ✅
| Silent / Mute | ✅ | ✅ | ✅ | ✅
| Do not disturb | ✅ | ✅ | ✅ | Silenced
| Sleep mode | ✅ | ✅ | ✅ | Silenced
| While playing other media| ✅ | ✅ | ✅ | ✅
| App killed | 🤖 | 🤖 | 🤖 | ✅
| | Sound | Vibrate | Volume | Notification
| ------------------------ | ----- | ------- | -------| -------
| Locked screen | ✅ | ✅ | ✅ | ✅
| Silent / Mute | ✅ | ✅ | ✅ | ✅
| Do not disturb | ✅ | ✅ | ✅ | Silenced
| Sleep mode | ✅ | ✅ | ✅ | Silenced
| While playing other media| ✅ | ✅ | ✅ | ✅
| App killed | 🤖 | 🤖 | 🤖 | ✅

✅ : iOS and Android
🤖 : Android only.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ class AlarmService : Service() {
Log.d("AlarmService", "Error while invoking alarmRinging channel: $e")
}

if (volume != -1.0) {
if (volume >= 0.0 && volume <= 1.0) {
volumeService?.setVolume(volume, showSystemUI)
}

Expand Down
7 changes: 6 additions & 1 deletion example/lib/main.dart
Original file line number Diff line number Diff line change
Expand Up @@ -10,5 +10,10 @@ Future<void> main() async {

await Alarm.init(showDebugLogs: true);

runApp(const MaterialApp(home: ExampleAlarmHomeScreen()));
runApp(
MaterialApp(
theme: ThemeData(useMaterial3: false),
home: const ExampleAlarmHomeScreen(),
),
);
}
60 changes: 43 additions & 17 deletions example/lib/screens/edit_alarm.dart
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ class _ExampleAlarmEditScreenState extends State<ExampleAlarmEditScreen> {
late DateTime selectedDateTime;
late bool loopAudio;
late bool vibrate;
late bool volumeMax;
late double? volume;
late String assetAudio;

@override
Expand All @@ -31,13 +31,13 @@ class _ExampleAlarmEditScreenState extends State<ExampleAlarmEditScreen> {
selectedDateTime = selectedDateTime.copyWith(second: 0, millisecond: 0);
loopAudio = true;
vibrate = true;
volumeMax = false;
volume = null;
assetAudio = 'assets/marimba.mp3';
} else {
selectedDateTime = widget.alarmSettings!.dateTime;
loopAudio = widget.alarmSettings!.loopAudio;
vibrate = widget.alarmSettings!.vibrate;
volumeMax = widget.alarmSettings!.volumeMax;
volume = widget.alarmSettings!.volume;
assetAudio = widget.alarmSettings!.assetAudioPath;
}
}
Expand Down Expand Up @@ -87,7 +87,7 @@ class _ExampleAlarmEditScreenState extends State<ExampleAlarmEditScreen> {
dateTime: selectedDateTime,
loopAudio: loopAudio,
vibrate: vibrate,
volumeMax: volumeMax,
volume: volume,
assetAudioPath: assetAudio,
notificationTitle: 'Alarm example',
notificationBody: 'Your alarm ($id) is ringing',
Expand Down Expand Up @@ -190,19 +190,6 @@ class _ExampleAlarmEditScreenState extends State<ExampleAlarmEditScreen> {
),
],
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
'System volume max',
style: Theme.of(context).textTheme.titleMedium,
),
Switch(
value: volumeMax,
onChanged: (value) => setState(() => volumeMax = value),
),
],
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Expand Down Expand Up @@ -238,6 +225,45 @@ class _ExampleAlarmEditScreenState extends State<ExampleAlarmEditScreen> {
),
],
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
'Custom volume',
style: Theme.of(context).textTheme.titleMedium,
),
Switch(
value: volume != null,
onChanged: (value) =>
setState(() => volume = value ? 0.5 : null),
),
],
),
SizedBox(
height: 30,
child: volume != null
? Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Icon(
volume! > 0.7
? Icons.volume_up_rounded
: volume! > 0.1
? Icons.volume_down_rounded
: Icons.volume_mute_rounded,
),
Expanded(
child: Slider(
value: volume!,
onChanged: (value) {
setState(() => volume = value);
},
),
),
],
)
: const SizedBox(),
),
if (!creating)
TextButton(
onPressed: deleteAlarm,
Expand Down
4 changes: 3 additions & 1 deletion example/lib/screens/shortcut_button.dart
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,11 @@ class _ExampleAlarmHomeShortcutButtonState

Future<void> onPressButton(int delayInHours) async {
DateTime dateTime = DateTime.now().add(Duration(hours: delayInHours));
double? volume;

if (delayInHours != 0) {
dateTime = dateTime.copyWith(second: 0, millisecond: 0);
volume = 0.5;
}

setState(() => showMenu = false);
Expand All @@ -29,7 +31,7 @@ class _ExampleAlarmHomeShortcutButtonState
id: DateTime.now().millisecondsSinceEpoch % 10000,
dateTime: dateTime,
assetAudioPath: 'assets/marimba.mp3',
volumeMax: false,
volume: volume,
notificationTitle: 'Alarm example',
notificationBody:
'Shortcut button alarm with delay of $delayInHours hours',
Expand Down
18 changes: 9 additions & 9 deletions example/pubspec.lock
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ packages:
path: ".."
relative: true
source: path
version: "2.2.0"
version: "3.0.0-dev.1"
args:
dependency: transitive
description:
Expand Down Expand Up @@ -68,10 +68,10 @@ packages:
dependency: transitive
description:
name: dbus
sha256: "6f07cba3f7b3448d42d015bfd3d53fe12e5b36da2423f23838efc1d5fb31a263"
sha256: "365c771ac3b0e58845f39ec6deebc76e3276aa9922b0cc60840712094d9047ac"
url: "https://pub.dev"
source: hosted
version: "0.7.8"
version: "0.7.10"
fake_async:
dependency: transitive
description:
Expand Down Expand Up @@ -235,10 +235,10 @@ packages:
dependency: transitive
description:
name: plugin_platform_interface
sha256: da3fdfeccc4d4ff2da8f8c556704c08f912542c5fb3cf2233ed75372384a034d
sha256: f4f88d4a900933e7267e2b353594774fc0d07fb072b47eedcd5b54e1ea3269f8
url: "https://pub.dev"
source: hosted
version: "2.1.6"
version: "2.1.7"
shared_preferences:
dependency: transitive
description:
Expand Down Expand Up @@ -283,10 +283,10 @@ packages:
dependency: transitive
description:
name: shared_preferences_web
sha256: d762709c2bbe80626ecc819143013cc820fa49ca5e363620ee20a8b15a3e3daf
sha256: "7b15ffb9387ea3e237bb7a66b8a23d2147663d391cafc5c8f37b2e7b4bde5d21"
url: "https://pub.dev"
source: hosted
version: "2.2.1"
version: "2.2.2"
shared_preferences_windows:
dependency: transitive
description:
Expand Down Expand Up @@ -397,5 +397,5 @@ packages:
source: hosted
version: "6.4.2"
sdks:
dart: ">=3.2.0-194.0.dev <4.0.0"
flutter: ">=3.7.0"
dart: ">=3.2.0 <4.0.0"
flutter: ">=3.16.0"
25 changes: 14 additions & 11 deletions ios/Classes/SwiftAlarmPlugin.swift
Original file line number Diff line number Diff line change
Expand Up @@ -84,8 +84,13 @@ public class SwiftAlarmPlugin: NSObject, FlutterPlugin {
let loopAudio = args["loopAudio"] as! Bool
let fadeDuration = args["fadeDuration"] as! Double
let vibrationsEnabled = args["vibrate"] as! Bool
let volumeMax = args["volumeMax"] as! Bool
let volume = args["volume"] as? Double
let assetAudio = args["assetAudio"] as! String

var volumeFloat: Float? = nil
if let volumeValue = volume {
volumeFloat = Float(volumeValue)
}

if assetAudio.hasPrefix("assets/") {
let filename = registrar.lookupKey(forAsset: assetAudio)
Expand Down Expand Up @@ -146,7 +151,7 @@ public class SwiftAlarmPlugin: NSObject, FlutterPlugin {
fadeDuration: fadeDuration,
vibrationsEnabled: vibrationsEnabled,
audioLoop: loopAudio,
volumeMax: volumeMax
volume: volumeFloat
)
})

Expand Down Expand Up @@ -214,7 +219,7 @@ public class SwiftAlarmPlugin: NSObject, FlutterPlugin {
}
}

private func handleAlarmAfterDelay(id: Int, triggerTime: Date, fadeDuration: Double, vibrationsEnabled: Bool, audioLoop: Bool, volumeMax: Bool) {
private func handleAlarmAfterDelay(id: Int, triggerTime: Date, fadeDuration: Double, vibrationsEnabled: Bool, audioLoop: Bool, volume: Float?) {
guard let audioPlayer = self.audioPlayers[id], let storedTriggerTime = triggerTimes[id], triggerTime == storedTriggerTime else {
return
}
Expand All @@ -234,14 +239,12 @@ public class SwiftAlarmPlugin: NSObject, FlutterPlugin {
self.vibrate = false
}
}

if fadeDuration > 0.0 {
if volumeMax {
self.setVolume(volume: 1.0, enable: true)
}
audioPlayer.setVolume(1.0, fadeDuration: fadeDuration)
} else if volumeMax {
self.setVolume(volume: 1.0, enable: true)

if let volumeValue = volume {
self.setVolume(volume: volumeValue, enable: true)
}
if fadeDuration > 0.0 {
audioPlayer.setVolume(1.0, fadeDuration: fadeDuration)
}
}

Expand Down
33 changes: 19 additions & 14 deletions lib/model/alarm_settings.dart
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,15 @@ class AlarmSettings {
/// If [loopAudio] is set to false, vibrations will stop when audio ends.
final bool vibrate;

/// If true, set system volume to maximum when [dateTime] is reached
/// and set it back to its previous value when alarm is stopped.
/// Else, use current system volume. Enabled by default.
final bool volumeMax;
/// Specifies the system volume level to be set at the designated [dateTime].
///
/// Accepts a value between 0 (mute) and 1 (maximum volume). When the alarm is triggered at [dateTime],
/// the system volume adjusts to this specified level. Upon stopping the alarm, the system volume reverts
/// to its prior setting.
///
/// If left unspecified or set to `null`, the current system volume at the time of the alarm will be used.
/// Defaults to `null`.
final double? volume;

/// Duration, in seconds, over which to fade the alarm ringtone.
/// Set to 0.0 by default, which means no fade.
Expand Down Expand Up @@ -52,7 +57,7 @@ class AlarmSettings {
hash = hash ^ assetAudioPath.hashCode;
hash = hash ^ loopAudio.hashCode;
hash = hash ^ vibrate.hashCode;
hash = hash ^ volumeMax.hashCode;
hash = hash ^ volume.hashCode;
hash = hash ^ fadeDuration.hashCode;
hash = hash ^ (notificationTitle.hashCode);
hash = hash ^ (notificationBody.hashCode);
Expand All @@ -73,7 +78,7 @@ class AlarmSettings {
required this.assetAudioPath,
this.loopAudio = true,
this.vibrate = true,
this.volumeMax = true,
this.volume,
this.fadeDuration = 0.0,
required this.notificationTitle,
required this.notificationBody,
Expand All @@ -87,11 +92,11 @@ class AlarmSettings {
dateTime: DateTime.fromMicrosecondsSinceEpoch(json['dateTime'] as int),
assetAudioPath: json['assetAudioPath'] as String,
loopAudio: json['loopAudio'] as bool,
vibrate: json['vibrate'] as bool,
volumeMax: json['volumeMax'] as bool,
vibrate: json['vibrate'] as bool? ?? true,
volume: json['volume'] as double?,
fadeDuration: json['fadeDuration'] as double,
notificationTitle: json['notificationTitle'] as String,
notificationBody: json['notificationBody'] as String,
notificationTitle: json['notificationTitle'] as String? ?? '',
notificationBody: json['notificationBody'] as String? ?? '',
enableNotificationOnKill:
json['enableNotificationOnKill'] as bool? ?? true,
androidFullScreenIntent:
Expand All @@ -106,7 +111,7 @@ class AlarmSettings {
String? assetAudioPath,
bool? loopAudio,
bool? vibrate,
bool? volumeMax,
double? volume,
double? fadeDuration,
String? notificationTitle,
String? notificationBody,
Expand All @@ -119,7 +124,7 @@ class AlarmSettings {
assetAudioPath: assetAudioPath ?? this.assetAudioPath,
loopAudio: loopAudio ?? this.loopAudio,
vibrate: vibrate ?? this.vibrate,
volumeMax: volumeMax ?? this.volumeMax,
volume: volume ?? this.volume,
fadeDuration: fadeDuration ?? this.fadeDuration,
notificationTitle: notificationTitle ?? this.notificationTitle,
notificationBody: notificationBody ?? this.notificationBody,
Expand All @@ -137,7 +142,7 @@ class AlarmSettings {
'assetAudioPath': assetAudioPath,
'loopAudio': loopAudio,
'vibrate': vibrate,
'volumeMax': volumeMax,
'volume': volume,
'fadeDuration': fadeDuration,
'notificationTitle': notificationTitle,
'notificationBody': notificationBody,
Expand Down Expand Up @@ -165,7 +170,7 @@ class AlarmSettings {
assetAudioPath == other.assetAudioPath &&
loopAudio == other.loopAudio &&
vibrate == other.vibrate &&
volumeMax == other.volumeMax &&
volume == other.volume &&
fadeDuration == other.fadeDuration &&
notificationTitle == other.notificationTitle &&
notificationBody == other.notificationBody &&
Expand Down
Loading

0 comments on commit 7709568

Please sign in to comment.