Compare commits

...

3 Commits

14 changed files with 226 additions and 60 deletions

View File

@ -33,10 +33,10 @@ class AlarmService : Service(), OnPreparedListener {
val pendingStop = val pendingStop =
PendingIntent.getBroadcast(context, 0, stopBroadcast, PendingIntent.FLAG_IMMUTABLE) PendingIntent.getBroadcast(context, 0, stopBroadcast, PendingIntent.FLAG_IMMUTABLE)
return NotificationCompat.Builder(context, MainActivity.CHANNEL_ID_PENDING) return NotificationCompat.Builder(context, MainActivity.CHANNEL_ID_PENDING)
.setSmallIcon(R.drawable.ic_baseline_hourglass_bottom_24).setContentTitle("Resting") .setSmallIcon(R.drawable.baseline_hourglass_bottom_24).setContentTitle("Resting")
.setContentIntent(pendingContent) .setContentIntent(pendingContent)
.addAction(R.drawable.ic_baseline_stop_24, "Stop", pendingStop) .addAction(R.drawable.launch_background, "Stop", pendingStop)
.addAction(R.drawable.ic_baseline_stop_24, "Add 1 min", pendingAdd) .addAction(R.drawable.launch_background, "Add 1 min", pendingAdd)
.setDeleteIntent(pendingStop) .setDeleteIntent(pendingStop)
} }

View File

@ -18,8 +18,8 @@ import io.flutter.embedding.engine.FlutterEngine
import io.flutter.plugin.common.MethodChannel import io.flutter.plugin.common.MethodChannel
import kotlin.math.floor import kotlin.math.floor
@RequiresApi(Build.VERSION_CODES.O)
class MainActivity : FlutterActivity() { class MainActivity : FlutterActivity() {
@RequiresApi(Build.VERSION_CODES.O)
override fun configureFlutterEngine(flutterEngine: FlutterEngine) { override fun configureFlutterEngine(flutterEngine: FlutterEngine) {
super.configureFlutterEngine(flutterEngine) super.configureFlutterEngine(flutterEngine)
MethodChannel(flutterEngine.dartExecutor.binaryMessenger, FLUTTER_CHANNEL).setMethodCallHandler { MethodChannel(flutterEngine.dartExecutor.binaryMessenger, FLUTTER_CHANNEL).setMethodCallHandler {
@ -38,7 +38,6 @@ class MainActivity : FlutterActivity() {
private var running = false private var running = false
private val stopReceiver = object : BroadcastReceiver() { private val stopReceiver = object : BroadcastReceiver() {
@RequiresApi(Build.VERSION_CODES.O)
override fun onReceive(context: Context?, intent: Intent?) { override fun onReceive(context: Context?, intent: Intent?) {
Log.d("MainActivity", "Received stop broadcast intent") Log.d("MainActivity", "Received stop broadcast intent")
stop() stop()
@ -46,7 +45,6 @@ class MainActivity : FlutterActivity() {
} }
private val addReceiver = object : BroadcastReceiver() { private val addReceiver = object : BroadcastReceiver() {
@RequiresApi(Build.VERSION_CODES.O)
override fun onReceive(context: Context?, intent: Intent?) { override fun onReceive(context: Context?, intent: Intent?) {
add() add()
} }
@ -55,7 +53,6 @@ class MainActivity : FlutterActivity() {
init { init {
} }
@RequiresApi(api = Build.VERSION_CODES.O)
fun add() { fun add() {
Log.d("MainActivity", "Add 1 min to alarm.") Log.d("MainActivity", "Add 1 min to alarm.")
countdownTimer?.cancel() countdownTimer?.cancel()
@ -69,7 +66,6 @@ class MainActivity : FlutterActivity() {
context.stopService(intent) context.stopService(intent)
} }
@RequiresApi(api = Build.VERSION_CODES.O)
fun stop() { fun stop() {
Log.d("MainActivity", "Stop alarm.") Log.d("MainActivity", "Stop alarm.")
countdownTimer?.cancel() countdownTimer?.cancel()
@ -81,7 +77,6 @@ class MainActivity : FlutterActivity() {
manager.cancel(NOTIFICATION_ID_PENDING) manager.cancel(NOTIFICATION_ID_PENDING)
} }
@RequiresApi(api = Build.VERSION_CODES.O)
fun timer(milliseconds: Int) { fun timer(milliseconds: Int) {
context.registerReceiver(stopReceiver, IntentFilter(STOP_BROADCAST)) context.registerReceiver(stopReceiver, IntentFilter(STOP_BROADCAST))
context.registerReceiver(addReceiver, IntentFilter(ADD_BROADCAST)) context.registerReceiver(addReceiver, IntentFilter(ADD_BROADCAST))
@ -96,7 +91,6 @@ class MainActivity : FlutterActivity() {
running = true running = true
} }
@RequiresApi(Build.VERSION_CODES.O)
private fun getTimer( private fun getTimer(
endMs: Int, endMs: Int,
): CountDownTimer { ): CountDownTimer {
@ -125,7 +119,6 @@ class MainActivity : FlutterActivity() {
} }
@SuppressLint("UnspecifiedImmutableFlag") @SuppressLint("UnspecifiedImmutableFlag")
@RequiresApi(Build.VERSION_CODES.M)
private fun getBuilder(): NotificationCompat.Builder { private fun getBuilder(): NotificationCompat.Builder {
val contentIntent = Intent(context, MainActivity::class.java) val contentIntent = Intent(context, MainActivity::class.java)
val pendingContent = val pendingContent =
@ -140,14 +133,13 @@ class MainActivity : FlutterActivity() {
val pendingStop = val pendingStop =
PendingIntent.getBroadcast(context, 0, stopBroadcast, PendingIntent.FLAG_IMMUTABLE) PendingIntent.getBroadcast(context, 0, stopBroadcast, PendingIntent.FLAG_IMMUTABLE)
return NotificationCompat.Builder(context, CHANNEL_ID_PENDING) return NotificationCompat.Builder(context, CHANNEL_ID_PENDING)
.setSmallIcon(R.drawable.ic_baseline_hourglass_bottom_24).setContentTitle("Resting") .setSmallIcon(R.drawable.baseline_hourglass_bottom_24).setContentTitle("Resting")
.setContentIntent(pendingContent) .setContentIntent(pendingContent)
.addAction(R.drawable.ic_baseline_stop_24, "Stop", pendingStop) .addAction(R.drawable.baseline_hourglass_bottom_24, "Stop", pendingStop)
.addAction(R.drawable.ic_baseline_stop_24, "Add 1 min", pendingAdd) .addAction(R.drawable.baseline_hourglass_bottom_24, "Add 1 min", pendingAdd)
.setDeleteIntent(pendingStop) .setDeleteIntent(pendingStop)
} }
@RequiresApi(Build.VERSION_CODES.O)
private fun getManager(): NotificationManager { private fun getManager(): NotificationManager {
val notificationManager = context.getSystemService( val notificationManager = context.getSystemService(
NotificationManager::class.java NotificationManager::class.java

View File

@ -0,0 +1,5 @@
<vector android:height="24dp" android:tint="#000000"
android:viewportHeight="24" android:viewportWidth="24"
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="@android:color/white" android:pathData="M18,22l-0.01,-6L14,12l3.99,-4.01L18,2H6v6l4,4l-4,3.99V22H18zM8,7.5V4h8v3.5l-4,4L8,7.5z"/>
</vector>

View File

@ -0,0 +1,53 @@
import 'package:flutter/material.dart';
class DynamicColorScheme extends StatefulWidget {
final Color Function(Brightness brightness) data;
final Widget Function(BuildContext context, ColorScheme colorScheme) builder;
const DynamicColorScheme({
required this.data,
required this.builder,
Key? key,
}) : super(key: key);
@override
createState() => _DynamicColorSchemeState();
}
class _DynamicColorSchemeState extends State<DynamicColorScheme> {
late final ValueNotifier<Brightness> brightness;
@override
void initState() {
super.initState();
brightness = ValueNotifier(MediaQuery.of(context).platformBrightness);
}
@override
void didChangeDependencies() {
super.didChangeDependencies();
brightness.value = MediaQuery.of(context).platformBrightness;
}
@override
Widget build(BuildContext context) {
return ValueListenableBuilder<Brightness>(
valueListenable: brightness,
builder: (context, platformBrightness, child) {
final colorScheme = ColorScheme.fromSwatch(
brightness: platformBrightness,
primarySwatch: Colors.blue,
accentColor: Colors.blueAccent,
).copyWith(
secondary: Colors.red,
);
final color = widget.data(platformBrightness);
return widget.builder(
context,
colorScheme.copyWith(
primary: color,
));
},
);
}
}

View File

@ -25,10 +25,9 @@ class MyApp extends StatelessWidget {
return MaterialApp( return MaterialApp(
title: 'Gym App', title: 'Gym App',
theme: ThemeData( themeMode: ThemeMode.system,
primarySwatch: Colors.blue, darkTheme: ThemeData.dark(),
visualDensity: VisualDensity.adaptivePlatformDensity, theme: ThemeData.light(),
),
initialRoute: '/home', initialRoute: '/home',
routes: routes, routes: routes,
navigatorKey: navigatorKey, navigatorKey: navigatorKey,

View File

@ -2,6 +2,7 @@ import 'package:flutter/material.dart';
import 'package:flutter/material.dart' as material; import 'package:flutter/material.dart' as material;
import 'package:fmassive/database.dart'; import 'package:fmassive/database.dart';
import 'package:fmassive/main.dart'; import 'package:fmassive/main.dart';
import 'package:fmassive/sound_picker.dart';
import 'package:moor/moor.dart'; import 'package:moor/moor.dart';
class SettingsPage extends StatelessWidget { class SettingsPage extends StatelessWidget {
@ -47,7 +48,6 @@ class _SettingsPageState extends State<_SettingsPage> {
return const Center(child: CircularProgressIndicator()); return const Center(child: CircularProgressIndicator());
return SingleChildScrollView( return SingleChildScrollView(
padding: const EdgeInsets.all(8.0),
child: material.Column( child: material.Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
@ -105,46 +105,14 @@ class _SettingsPageState extends State<_SettingsPage> {
.write(SettingsCompanion(steps: Value(value))); .write(SettingsCompanion(steps: Value(value)));
}, },
), ),
TextField( Center(
decoration: const InputDecoration( child: SoundPicker(
labelText: 'Sound', path: settings.sound,
), onSelect: (path) {
onChanged: (value) { db
db .update(db.settings)
.update(db.settings) .write(SettingsCompanion(sound: Value(path)));
.write(SettingsCompanion(sound: Value(value))); })),
},
),
TextField(
decoration: const InputDecoration(
labelText: 'Light Color',
),
onChanged: (value) {
db
.update(db.settings)
.write(SettingsCompanion(lightColor: Value(value)));
},
),
TextField(
decoration: const InputDecoration(
labelText: 'Dark Color',
),
onChanged: (value) {
db
.update(db.settings)
.write(SettingsCompanion(darkColor: Value(value)));
},
),
TextField(
decoration: const InputDecoration(
labelText: 'Date',
),
onChanged: (value) {
db
.update(db.settings)
.write(SettingsCompanion(date: Value(value)));
},
),
], ],
), ),
); );

43
lib/sound_picker.dart Normal file
View File

@ -0,0 +1,43 @@
import 'package:audioplayers/audioplayers.dart';
import 'package:file_picker/file_picker.dart';
import 'package:flutter/material.dart';
import 'package:path/path.dart';
class SoundPicker extends StatefulWidget {
const SoundPicker({super.key, required this.onSelect, required this.path});
final Function(String path) onSelect;
final String? path;
@override
createState() => _SoundPickerState();
}
class _SoundPickerState extends State<SoundPicker> {
final audioPlayer = AudioPlayer();
@override
void dispose() {
audioPlayer.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return ElevatedButton(
onPressed: () async {
FilePickerResult? result = await FilePicker.platform.pickFiles(
type: FileType.audio,
);
if (result == null) return;
final path = result.files.first.path;
if (path == null) return;
await audioPlayer.play(DeviceFileSource(path));
widget.onSelect(path);
},
child: Text(widget.path != null
? "Sound: ${basename(widget.path!)}"
: 'Alarm sound'),
);
}
}

View File

@ -6,9 +6,13 @@
#include "generated_plugin_registrant.h" #include "generated_plugin_registrant.h"
#include <audioplayers_linux/audioplayers_linux_plugin.h>
#include <sqlite3_flutter_libs/sqlite3_flutter_libs_plugin.h> #include <sqlite3_flutter_libs/sqlite3_flutter_libs_plugin.h>
void fl_register_plugins(FlPluginRegistry* registry) { void fl_register_plugins(FlPluginRegistry* registry) {
g_autoptr(FlPluginRegistrar) audioplayers_linux_registrar =
fl_plugin_registry_get_registrar_for_plugin(registry, "AudioplayersLinuxPlugin");
audioplayers_linux_plugin_register_with_registrar(audioplayers_linux_registrar);
g_autoptr(FlPluginRegistrar) sqlite3_flutter_libs_registrar = g_autoptr(FlPluginRegistrar) sqlite3_flutter_libs_registrar =
fl_plugin_registry_get_registrar_for_plugin(registry, "Sqlite3FlutterLibsPlugin"); fl_plugin_registry_get_registrar_for_plugin(registry, "Sqlite3FlutterLibsPlugin");
sqlite3_flutter_libs_plugin_register_with_registrar(sqlite3_flutter_libs_registrar); sqlite3_flutter_libs_plugin_register_with_registrar(sqlite3_flutter_libs_registrar);

View File

@ -3,6 +3,7 @@
# #
list(APPEND FLUTTER_PLUGIN_LIST list(APPEND FLUTTER_PLUGIN_LIST
audioplayers_linux
sqlite3_flutter_libs sqlite3_flutter_libs
) )

View File

@ -5,11 +5,13 @@
import FlutterMacOS import FlutterMacOS
import Foundation import Foundation
import audioplayers_darwin
import path_provider_foundation import path_provider_foundation
import sqflite import sqflite
import sqlite3_flutter_libs import sqlite3_flutter_libs
func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
AudioplayersDarwinPlugin.register(with: registry.registrar(forPlugin: "AudioplayersDarwinPlugin"))
PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin")) PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin"))
SqflitePlugin.register(with: registry.registrar(forPlugin: "SqflitePlugin")) SqflitePlugin.register(with: registry.registrar(forPlugin: "SqflitePlugin"))
Sqlite3FlutterLibsPlugin.register(with: registry.registrar(forPlugin: "Sqlite3FlutterLibsPlugin")) Sqlite3FlutterLibsPlugin.register(with: registry.registrar(forPlugin: "Sqlite3FlutterLibsPlugin"))

View File

@ -41,6 +41,62 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.10.0" version: "2.10.0"
audioplayers:
dependency: "direct main"
description:
name: audioplayers
sha256: "6063c05f987596ba7a3dad9bb9a5d8adfa5e7c07b9bae5301b27c11d0b3a239f"
url: "https://pub.dev"
source: hosted
version: "4.0.1"
audioplayers_android:
dependency: transitive
description:
name: audioplayers_android
sha256: fb6bca878ad175d8f6ddc0e0a2d4226d81fa7c10747c12db420e96c7a096b2cc
url: "https://pub.dev"
source: hosted
version: "3.0.1"
audioplayers_darwin:
dependency: transitive
description:
name: audioplayers_darwin
sha256: c4a56c49347b2e85ac4e1efea218948ca0fba87f04d2a3d3de07ce2410037038
url: "https://pub.dev"
source: hosted
version: "4.0.1"
audioplayers_linux:
dependency: transitive
description:
name: audioplayers_linux
sha256: "897e24f190232a3fbb88134b062aa83a9240f55789b5e8d17c114283284ef56b"
url: "https://pub.dev"
source: hosted
version: "2.0.1"
audioplayers_platform_interface:
dependency: transitive
description:
name: audioplayers_platform_interface
sha256: "3a90a46198d375fc7d47bc1d3070c8fd8863b6469b7d87ca80f953efb090f976"
url: "https://pub.dev"
source: hosted
version: "5.0.0"
audioplayers_web:
dependency: transitive
description:
name: audioplayers_web
sha256: "4f5dcbfec0bf98ea09e243d5f5b64ea43a4e6710a2f292724bed16cdba3c691e"
url: "https://pub.dev"
source: hosted
version: "3.0.1"
audioplayers_windows:
dependency: transitive
description:
name: audioplayers_windows
sha256: "010f575653c01ccbe9756050b18df83d89426740e04b684f6438aa26c775a965"
url: "https://pub.dev"
source: hosted
version: "2.0.1"
boolean_selector: boolean_selector:
dependency: transitive dependency: transitive
description: description:
@ -241,6 +297,14 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "6.1.4" version: "6.1.4"
file_picker:
dependency: "direct main"
description:
name: file_picker
sha256: dcde5ad1a0cebcf3715ea3f24d0db1888bf77027a26c77d7779e8ef63b8ade62
url: "https://pub.dev"
source: hosted
version: "5.2.9"
fixnum: fixnum:
dependency: transitive dependency: transitive
description: description:
@ -262,11 +326,24 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.0.1" version: "2.0.1"
flutter_plugin_android_lifecycle:
dependency: transitive
description:
name: flutter_plugin_android_lifecycle
sha256: c224ac897bed083dabf11f238dd11a239809b446740be0c2044608c50029ffdf
url: "https://pub.dev"
source: hosted
version: "2.0.9"
flutter_test: flutter_test:
dependency: "direct dev" dependency: "direct dev"
description: flutter description: flutter
source: sdk source: sdk
version: "0.0.0" version: "0.0.0"
flutter_web_plugins:
dependency: transitive
description: flutter
source: sdk
version: "0.0.0"
frontend_server_client: frontend_server_client:
dependency: transitive dependency: transitive
description: description:
@ -291,6 +368,14 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.2.0" version: "2.2.0"
http:
dependency: transitive
description:
name: http
sha256: "6aa2946395183537c8b880962d935877325d6a09a2867c3970c05c0fed6ac482"
url: "https://pub.dev"
source: hosted
version: "0.13.5"
http_multi_server: http_multi_server:
dependency: transitive dependency: transitive
description: description:
@ -672,6 +757,14 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.3.1" version: "1.3.1"
uuid:
dependency: transitive
description:
name: uuid
sha256: "648e103079f7c64a36dc7d39369cabb358d377078a051d6ae2ad3aa539519313"
url: "https://pub.dev"
source: hosted
version: "3.0.7"
vector_math: vector_math:
dependency: transitive dependency: transitive
description: description:

View File

@ -42,6 +42,8 @@ dependencies:
path_provider: ^2.0.14 path_provider: ^2.0.14
sqlite3_flutter_libs: ^0.5.13 sqlite3_flutter_libs: ^0.5.13
moor: ^4.6.1+1 moor: ^4.6.1+1
file_picker: ^5.2.9
audioplayers: ^4.0.1
dev_dependencies: dev_dependencies:
flutter_test: flutter_test:

View File

@ -6,9 +6,12 @@
#include "generated_plugin_registrant.h" #include "generated_plugin_registrant.h"
#include <audioplayers_windows/audioplayers_windows_plugin.h>
#include <sqlite3_flutter_libs/sqlite3_flutter_libs_plugin.h> #include <sqlite3_flutter_libs/sqlite3_flutter_libs_plugin.h>
void RegisterPlugins(flutter::PluginRegistry* registry) { void RegisterPlugins(flutter::PluginRegistry* registry) {
AudioplayersWindowsPluginRegisterWithRegistrar(
registry->GetRegistrarForPlugin("AudioplayersWindowsPlugin"));
Sqlite3FlutterLibsPluginRegisterWithRegistrar( Sqlite3FlutterLibsPluginRegisterWithRegistrar(
registry->GetRegistrarForPlugin("Sqlite3FlutterLibsPlugin")); registry->GetRegistrarForPlugin("Sqlite3FlutterLibsPlugin"));
} }

View File

@ -3,6 +3,7 @@
# #
list(APPEND FLUTTER_PLUGIN_LIST list(APPEND FLUTTER_PLUGIN_LIST
audioplayers_windows
sqlite3_flutter_libs sqlite3_flutter_libs
) )