Skip to content

Commit 99fc0a8

Browse files
committed
more intuitive saving and alarm queuing
1 parent 976077a commit 99fc0a8

File tree

8 files changed

+126
-24
lines changed

8 files changed

+126
-24
lines changed

README.md

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,21 @@
22
An app for controling [OpenShock](https://openshock.org/) shockers and even setting alarms with custom tones.
33
Based partly on https://github.com/mvarendorff/random-alarm/
44

5+
# Planned features
6+
- [ ] Grouping of shockers
7+
- [ ] (Un)Pausing of shockers
8+
- [ ] Alarm tones
9+
- [ ] Login with username/email and password
10+
- [ ] Random delay
11+
- [ ] (Big controls mode)
12+
- [ ] Renaming of shockers (global)
13+
- [ ] Change sharing limits
14+
- [ ] Redeem share codes
15+
- [ ] Create share codes
16+
- [ ] Viewing of logs
17+
- [ ] Linux support
18+
19+
520
## Getting Started
621

722
This project is a starting point for a Flutter application.

lib/components/alarm_item.dart

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ class AlarmItemState extends State<AlarmItem> {
6666
crossAxisAlignment: CrossAxisAlignment.start,
6767
children: <Widget>[
6868
Text(alarm.name),
69-
EditAlarmTime(alarm: this.alarm),
69+
EditAlarmTime(alarm: this.alarm, manager: this.manager,),
7070
DateRow(alarm: alarm)
7171
],
7272
),
@@ -79,6 +79,7 @@ class AlarmItemState extends State<AlarmItem> {
7979
onChanged: (value) {
8080
setState(() {
8181
alarm.active = value;
82+
_save();
8283
});
8384
}),
8485
],)

lib/components/edit_alarm_time.dart

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,25 @@
11
import 'package:flutter/material.dart';
22
import 'package:flutter_mobx/flutter_mobx.dart';
3+
import 'package:shock_alarm_app/services/alarm_list_manager.dart';
34

45
import '../stores/alarm_store.dart';
56

67
class EditAlarmTime extends StatefulWidget {
78
final ObservableAlarmBase alarm;
9+
final AlarmListManager manager;
810

9-
const EditAlarmTime({Key? key, required this.alarm}) : super(key: key);
11+
12+
const EditAlarmTime({Key? key, required this.alarm, required this.manager}) : super(key: key);
1013

1114
@override
12-
State<StatefulWidget> createState() => EditAlarmTimeState(alarm);
15+
State<StatefulWidget> createState() => EditAlarmTimeState(alarm, manager);
1316
}
1417

1518
class EditAlarmTimeState extends State<EditAlarmTime> {
1619
final ObservableAlarmBase alarm;
20+
final AlarmListManager manager;
1721

18-
EditAlarmTimeState(this.alarm);
22+
EditAlarmTimeState(this.alarm, this.manager);
1923

2024
@override
2125
Widget build(BuildContext context) {
@@ -41,6 +45,7 @@ class EditAlarmTimeState extends State<EditAlarmTime> {
4145
setState(() {
4246
alarm.hour = time.hour;
4347
alarm.minute = time.minute;
48+
manager.saveAlarm(alarm);
4449
});
4550
},
4651
),

lib/components/token_item.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ class TokenItemState extends State<TokenItem> {
7777
onChanged: (newToken) => token.token = newToken,
7878
),
7979
Row(
80-
mainAxisAlignment: MainAxisAlignment.spaceBetween,
80+
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
8181
children: <Widget>[
8282
IconButton(
8383
icon: Icon(Icons.delete),

lib/main.dart

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,15 +20,23 @@ Future requestPermissions() async{
2020
}
2121
void main() async {
2222
WidgetsFlutterBinding.ensureInitialized();
23-
//await AndroidAlarmManager.initialize();
24-
//await AndroidAlarmManager.oneShot(Duration(seconds: 10), 0, alarmCallback, alarmClock: true);
23+
await AndroidAlarmManager.initialize();
24+
await requestPermissions();
2525

26-
//await requestPermissions();
2726
runApp(MyApp(null));
2827
}
2928

3029
@pragma('vm:entry-point')
31-
void alarmCallback(int id) {
30+
void alarmCallback(int id) async {
31+
32+
AlarmListManager manager = AlarmListManager();
33+
await manager.loadAllFromStorage();
34+
manager.getAlarms().forEach((element) {
35+
print("Checking alarm");
36+
if(element.active && id ==element.id) {
37+
element.trigger(manager, true);
38+
}
39+
});
3240
print("Woah");
3341
}
3442

lib/screens/home.dart

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -81,13 +81,14 @@ class HomeScreenState extends State<HomeScreen> {
8181

8282
@override
8383
Widget build(BuildContext context) {
84+
manager.context = context;
8485
return Column(
8586
children: <Widget>[
8687
Text(
8788
'Your alarms',
8889
style: TextStyle(fontSize: 28, color: Theme.of(context).textTheme.headlineMedium?.color),
8990
),
90-
Text("Alarms are currently not working",
91+
Text("Alarms are currently semi working",
9192
style: TextStyle(fontSize: 20),),
9293
Flexible(
9394
child: Observer(
@@ -106,7 +107,7 @@ class HomeScreenState extends State<HomeScreen> {
106107
onPressed: () {
107108
TimeOfDay tod = TimeOfDay.fromDateTime(DateTime.now());
108109
final newAlarm = new ObservableAlarmBase(
109-
id: DateTime.now().millisecondsSinceEpoch,
110+
id: manager.getNewAlarmId(),
110111
name: 'New Alarm',
111112
hour: tod.hour,
112113
minute: tod.minute,

lib/services/alarm_list_manager.dart

Lines changed: 54 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import 'package:flutter/material.dart';
12
import 'package:shock_alarm_app/services/openshock.dart';
23
import 'package:shared_preferences/shared_preferences.dart';
34
import 'package:android_alarm_manager_plus/android_alarm_manager_plus.dart';
@@ -17,6 +18,8 @@ class AlarmListManager {
1718

1819
Function? reloadAllMethod;
1920

21+
BuildContext? context;
22+
2023

2124
Future loadAllFromStorage() async {
2225
final SharedPreferences prefs = await SharedPreferences.getInstance();
@@ -49,6 +52,30 @@ class AlarmListManager {
4952
}
5053
}
5154

55+
void rescheduleAlarms() async {
56+
for (var alarm in _alarms) {
57+
if (alarm.active) {
58+
await alarm.schedule(this);
59+
}
60+
}
61+
}
62+
63+
int getNewAlarmId() {
64+
int id = 0;
65+
bool foundNew = true;
66+
while (!foundNew) {
67+
foundNew = true;
68+
for (var alarm in _alarms) {
69+
if (alarm.id == id) {
70+
id++;
71+
foundNew = false;
72+
break;
73+
}
74+
}
75+
}
76+
return id;
77+
}
78+
5279
saveAlarm(ObservableAlarmBase alarm) async {
5380
final index =
5481
_alarms.indexWhere((findAlarm) => alarm.id == findAlarm.id);
@@ -58,14 +85,15 @@ class AlarmListManager {
5885
} else {
5986
_alarms[index] = alarm;
6087
}
61-
final SharedPreferences prefs = await SharedPreferences.getInstance();
6288
rebuildAlarmShockers();
63-
prefs.setString("alarms", jsonEncode(_alarms));
89+
rescheduleAlarms();
90+
saveAlarms();
6491
}
6592

6693
Future updateShockerStore() async {
6794
List<Shocker> shockers = [];
68-
for(var token in _tokens) {
95+
List<Token> tokensCopy = this._tokens.toList(); // create a copy
96+
for(var token in tokensCopy) {
6997
OpenShockClient client = OpenShockClient();
7098
token.name = await client.getNameForToken(token);
7199
List<Shocker> s = await client.GetShockersForToken(token);
@@ -78,8 +106,8 @@ class AlarmListManager {
78106
}
79107
this.shockers.clear();
80108
this.shockers.addAll(shockers);
81-
final SharedPreferences prefs = await SharedPreferences.getInstance();
82-
prefs.setString("shockers", jsonEncode(shockers));
109+
saveShockers();
110+
saveTokens();
83111
updateHubList();
84112
rebuildAlarmShockers();
85113
reloadAllMethod!();
@@ -92,8 +120,7 @@ class AlarmListManager {
92120
} else {
93121
_tokens[index] = token;
94122
}
95-
final SharedPreferences prefs = await SharedPreferences.getInstance();
96-
prefs.setString("tokens", jsonEncode(_tokens));
123+
saveTokens();
97124
updateShockerStore();
98125
//await _storage.writeList(_tokens.tokens);
99126
}
@@ -125,24 +152,39 @@ class AlarmListManager {
125152
}
126153
}
127154

128-
getAlarms() {
155+
List<ObservableAlarmBase> getAlarms() {
129156
return _alarms;
130157
}
131158

132159
getTokens() {
133160
return _tokens;
134161
}
135162

163+
void saveShockers() async {
164+
final SharedPreferences prefs = await SharedPreferences.getInstance();
165+
prefs.setString("shockers", jsonEncode(shockers));
166+
}
167+
168+
void saveAlarms() async {
169+
final SharedPreferences prefs = await SharedPreferences.getInstance();
170+
prefs.setString("alarms", jsonEncode(_alarms));
171+
}
172+
173+
void saveTokens() async {
174+
final SharedPreferences prefs = await SharedPreferences.getInstance();
175+
prefs.setString("tokens", jsonEncode(_tokens));
176+
}
177+
136178
void deleteToken(Token token) {
137179
_tokens.removeWhere((findToken) => token.id == findToken.id);
138-
//await _storage.writeList(_tokens.tokens);
180+
saveTokens();
139181
}
140182

141183
Token? getToken(int id) {
142184
return _tokens.firstWhere((findToken) => id == findToken.id);
143185
}
144186

145-
void sendShock(ControlType type, Shocker shocker, int currentIntensity, int currentDuration) {
187+
void sendShock(ControlType type, Shocker shocker, int currentIntensity, int currentDuration, {String customName = "ShockAlarm"}) {
146188
Control control = Control();
147189
control.intensity = currentIntensity;
148190
control.duration = currentDuration;
@@ -154,7 +196,8 @@ class AlarmListManager {
154196
print("Token not found");
155197
return;
156198
}
199+
print("Sending shock to ${shocker.name} with intensity $currentIntensity and duration $currentDuration");
157200
OpenShockClient client = OpenShockClient();
158-
client.sendControls(t, [control]);
201+
client.sendControls(t, [control], customName: customName);
159202
}
160203
}

lib/stores/alarm_store.dart

Lines changed: 31 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
1+
import 'package:android_alarm_manager_plus/android_alarm_manager_plus.dart';
2+
import 'package:flutter/material.dart';
13
import 'package:mobx/mobx.dart';
24
import 'package:shock_alarm_app/services/alarm_list_manager.dart';
35
import 'package:shock_alarm_app/services/openshock.dart';
6+
import '../main.dart';
47

58
class Token with Store {
69
Token(this.id, this.token, {this.server = "https://api.openshock.app", this.name=""});
@@ -85,15 +88,22 @@ class ObservableAlarmBase with Store {
8588
return [monday, tuesday, wednesday, thursday, friday, saturday, sunday];
8689
}
8790

88-
void trigger(AlarmListManager manager) {
91+
void trigger(AlarmListManager manager, bool disableIfApplicable) {
8992
for (var shocker in shockers) {
9093
if (shocker.enabled) {
91-
manager.sendShock(shocker.type!, shocker.shockerReference!, shocker.intensity, shocker.duration);
94+
manager.sendShock(shocker.type!, shocker.shockerReference!, shocker.intensity, shocker.duration, customName: name);
95+
}
96+
}
97+
if (disableIfApplicable) {
98+
if(!shouldSchedulePerWeekday()) {
99+
active = false;
100+
manager.saveAlarm(this);
92101
}
93102
}
94103
}
95104

96105
// Good enough for debugging for now
106+
@override
97107
toString() {
98108
return "active: $active, name: $name, hour: $hour, minute: $minute, days: $days";
99109
}
@@ -135,4 +145,23 @@ class ObservableAlarmBase with Store {
135145
}
136146
return a;
137147
}
148+
149+
bool shouldSchedulePerWeekday() {
150+
return days.any((element) {
151+
return element == true;
152+
});
153+
}
154+
155+
schedule(AlarmListManager manager) async {
156+
if (!shouldSchedulePerWeekday()) {
157+
// Schedule for next occurrance
158+
DateTime now = DateTime.now();
159+
DateTime nextOccurrance = DateTime(now.year, now.month, now.day, hour, minute);
160+
if (nextOccurrance.isBefore(now)) {
161+
nextOccurrance = nextOccurrance.add(Duration(days: 1));
162+
}
163+
ScaffoldMessenger.of(manager.context!).showSnackBar(SnackBar(content: Text("Scheduled alarm for ${nextOccurrance.toString()}")));
164+
AndroidAlarmManager.oneShotAt(nextOccurrance, id, alarmCallback, exact: true, wakeup: true);
165+
}
166+
}
138167
}

0 commit comments

Comments
 (0)