7 Commits
mvp2 ... mvp4

53 changed files with 174 additions and 80 deletions

View File

@@ -62,3 +62,13 @@ jobs:
name: flutter-web-build-latest name: flutter-web-build-latest
path: build/web path: build/web
if-no-files-found: error if-no-files-found: error
- name: Publish to Cloudflare Pages
uses: cloudflare/pages-action@v1
with:
apiToken: ${{ secrets.CLOUDFLARE_PAGES_DEPLOY }}
accountId: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
projectName: ything-radio
directory: build/web
# push directly to "production" on cloudflare pages
branch: main

View File

@@ -16,7 +16,7 @@ This app has been designed to run across all platforms!
- MacOS - MacOS
- Windows - Windows
- Linux - Linux
- Web - Web ([Live Demo](https://radio-demo.ything.app/))
Provide a single unified experience across *all* platforms for your users! Provide a single unified experience across *all* platforms for your users!
@@ -27,5 +27,4 @@ Coming Soon:
- Apple App Store Live Demo! - Apple App Store Live Demo!
- Google Play Store Live Demo! - Google Play Store Live Demo!
- Windows portable exe - Windows portable exe
- Web based live demo
- Screenshots / Demo Videos - Screenshots / Demo Videos

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.1 KiB

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 KiB

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.3 KiB

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.0 KiB

After

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.6 KiB

After

Width:  |  Height:  |  Size: 4.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.3 KiB

After

Width:  |  Height:  |  Size: 8.1 KiB

1
assets/appicon/radio.svg Normal file
View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="icon icon-tabler icons-tabler-outline icon-tabler-radio"><path stroke="none" d="M0 0h24v24H0z" fill="none"/><path d="M14 3l-9.371 3.749a1 1 0 0 0 -.629 .928v11.323a1 1 0 0 0 1 1h14a1 1 0 0 0 1 -1v-11a1 1 0 0 0 -1 -1h-14.5" /><path d="M4 12h16" /><path d="M7 12v-2" /><path d="M17 16v.01" /><path d="M13 16v.01" /></svg>

After

Width:  |  Height:  |  Size: 517 B

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 244 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 243 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 245 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 48 KiB

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 KiB

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.8 KiB

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.9 KiB

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.3 KiB

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.0 KiB

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.6 KiB

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.7 KiB

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.5 KiB

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.8 KiB

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.6 KiB

After

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.6 KiB

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.5 KiB

After

Width:  |  Height:  |  Size: 4.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.1 KiB

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.0 KiB

After

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.1 KiB

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.1 KiB

After

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.3 KiB

After

Width:  |  Height:  |  Size: 3.8 KiB

View File

@@ -6,35 +6,44 @@ class About extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return SafeZone( return Container(
child: DefaultTextStyle( decoration: const BoxDecoration(
style: Theme.of(context).textTheme.bodyLarge!, image: DecorationImage(
child: const SingleChildScrollView( image: AssetImage('assets/images/app-background2.jpg'),
child: Text( fit: BoxFit.cover,
'Ything Radio is an app that is intended to provide a demonstration of the ' opacity: 0.2,
'open source ything_radio app. This app is used to provide the ability for the ' ),
'"look and feel" of the app to be tested on real devices for those wishing to ' ),
'either use the code as a template for themselves; or, alternatively, have Ything LLC ' child: SafeZone(
'create a custom app for them!' child: DefaultTextStyle(
'\n\n' style: Theme.of(context).textTheme.bodyLarge!,
'This app intentionally does not provide a method to change the streaming source ' child: const SingleChildScrollView(
'as it is intended for use by internet radio stations to provide a dedicated app ' child: Text(
'for their radio station. This is not intended to be an app for generic usage for ' 'Ything Radio is an app that is intended to provide a demonstration of the '
'multiple radio stations, a discovery platform, or to facilitate user input for ' 'open source ything_radio app. This app is used to provide the ability for the '
'internet radio sites.' '"look and feel" of the app to be tested on real devices for those wishing to '
'\n\n' 'either use the code as a template for themselves; or, alternatively, have Ything LLC '
'This app has been designed to run across all platforms!' 'create a custom app for them!'
'\n\n' '\n\n'
'Android, iOS, MacOS, Windows, Linux, and Web!' 'This app intentionally does not provide a method to change the streaming source '
'\n\n' 'as it is intended for use by internet radio stations to provide a dedicated app '
'Have a single unified experience across all platforms for your users!' 'for their radio station. This is not intended to be an app for generic usage for '
'\n\n' 'multiple radio stations, a discovery platform, or to facilitate user input for '
'Want to have us modify this app for you? Reach out at info@ything.net ' 'internet radio sites.'
'We can add additional features for you! Schedule views, up next listings, ' '\n\n'
'and even custom user interactivity! ' 'This app has been designed to run across all platforms!'
'\n\n' '\n\n'
'We look forward to hearing from you soon! We would love to build your app!', 'Android, iOS, MacOS, Windows, Linux, and Web!'
textAlign: TextAlign.justify, '\n\n'
'Have a single unified experience across all platforms for your users!'
'\n\n'
'Want to have us modify this app for you? Reach out at info@ything.net '
'We can add additional features for you! Schedule views, up next listings, '
'and even custom user interactivity! '
'\n\n'
'We look forward to hearing from you soon! We would love to build your app!',
textAlign: TextAlign.justify,
),
), ),
), ),
), ),

View File

@@ -17,6 +17,36 @@ Future<void> setupListenHandler() async {
_session = await AudioSession.instance; _session = await AudioSession.instance;
await _session.configure(const AudioSessionConfiguration.music()); await _session.configure(const AudioSessionConfiguration.music());
//TODO: Do I need to handle these events? audioplayers may be doing it already
//_session.interruptionEventStream.listen((event) {
// if (event.begin) {
// switch (event.type) {
// case AudioInterruptionType.duck:
// _listenHandler.duck();
// break;
// case AudioInterruptionType.pause:
// case AudioInterruptionType.unknown:
// _listenHandler.pause();
// break;
// }
// } else {
// switch (event.type) {
// case AudioInterruptionType.duck:
// _listenHandler.unDuck();
// break;
// case AudioInterruptionType.pause:
// _listenHandler.play();
// break;
// case AudioInterruptionType.unknown:
// break;
// }
// }
//});
//_session.becomingNoisyEventStream.listen((_) {
// _listenHandler.pause();
//});
} }
ListenHandler getListenHandlder() => _listenHandler; ListenHandler getListenHandlder() => _listenHandler;

View File

@@ -38,12 +38,21 @@ class Links extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return DefaultTextStyle( return Container(
style: Theme.of(context).textTheme.headlineSmall!, decoration: const BoxDecoration(
child: SafeZone( image: DecorationImage(
child: Center( image: AssetImage('assets/images/app-background3.jpg'),
child: Column( fit: BoxFit.cover,
children: links.map((link) => link).toList(), opacity: 0.4,
),
),
child: DefaultTextStyle(
style: Theme.of(context).textTheme.headlineSmall!,
child: SafeZone(
child: Center(
child: Column(
children: links.map((link) => link).toList(),
),
), ),
), ),
), ),

View File

@@ -9,8 +9,17 @@ class Listen extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return const Center( return Container(
child: PlayControls(), decoration: const BoxDecoration(
image: DecorationImage(
image: AssetImage('assets/images/app-background.jpg'),
fit: BoxFit.cover,
opacity: 0.4,
),
),
child: const Center(
child: PlayControls(),
),
); );
} }
} }
@@ -27,8 +36,6 @@ class _PlayControlsState extends State<PlayControls>
@override @override
bool get wantKeepAlive => true; bool get wantKeepAlive => true;
bool isPlaying = false;
final ListenHandler _listenHandler = getListenHandlder(); final ListenHandler _listenHandler = getListenHandlder();
@override @override
@@ -37,15 +44,9 @@ class _PlayControlsState extends State<PlayControls>
print("Listen init"); print("Listen init");
_listenHandler.playbackState.listen((PlaybackState event) { _listenHandler.playbackState.listen((PlaybackState state) {
if (isPlaying == event.playing) { print("Playback state changed");
print("State unchanged, skipping setState()"); setState(() {});
return;
}
setState(() {
isPlaying = event.playing;
print("Updated playing state to $isPlaying");
});
}); });
} }
@@ -56,48 +57,33 @@ class _PlayControlsState extends State<PlayControls>
_listenHandler.stop(); _listenHandler.stop();
} }
Future<void> playPause() async {
print("playPause called");
_listenHandler.isPlaying()
? await _listenHandler.stop()
: await _listenHandler.play();
}
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
super.build(context); super.build(context);
print("Running build - Listen"); print("Running build - Listen");
if (isPlaying) {
_listenHandler.play();
_listenHandler.playbackState.add(PlaybackState(
controls: [
MediaControl.stop,
MediaControl.pause,
],
systemActions: {
MediaAction.stop,
MediaAction.pause,
},
playing: true,
));
} else {
_listenHandler.stop();
_listenHandler.playbackState.add(PlaybackState(
controls: [],
systemActions: {},
playing: false,
));
}
return ClipOval( return ClipOval(
child: Material( child: Material(
color: Theme.of(context).colorScheme.primaryContainer, color: Theme.of(context).colorScheme.primaryContainer,
child: InkWell( child: InkWell(
splashColor: Theme.of(context).colorScheme.onPrimaryContainer, splashColor: Theme.of(context).colorScheme.onPrimaryContainer,
onTap: () { onTap: () async {
setState(() { await playPause();
isPlaying = !isPlaying; setState(() {});
});
}, },
child: SizedBox( child: SizedBox(
width: 100, width: 100,
height: 100, height: 100,
child: Icon( child: Icon(
isPlaying ? Icons.stop : Icons.play_arrow, _listenHandler.isPlaying() ? Icons.stop : Icons.play_arrow,
color: Colors.white, color: Colors.white,
size: 50, size: 50,
), ),

View File

@@ -11,12 +11,59 @@ class ListenHandler extends BaseAudioHandler {
setup_player() { setup_player() {
_player.setReleaseMode(ReleaseMode.release); _player.setReleaseMode(ReleaseMode.release);
_player.onPlayerStateChanged.listen((event) {
print("Received audioplayers event: $event");
switch (event) {
case PlayerState.playing:
super.playbackState.add(PlaybackState(
controls: [
MediaControl.stop,
MediaControl.pause,
],
systemActions: {
MediaAction.stop,
MediaAction.pause,
},
playing: true,
));
break;
case PlayerState.paused:
case PlayerState.stopped:
case PlayerState.completed:
case PlayerState.disposed:
super.playbackState.add(PlaybackState(
controls: [],
systemActions: {},
playing: false,
));
break;
}
});
} }
ListenHandler() { ListenHandler() {
setup_player(); setup_player();
} }
bool isPlaying() => super.playbackState.value.playing;
double _duckVol = 0;
void duck() {
//TODO: Confirm I need to do this manually, it looks like audioplayers already does this
print("Duck requested");
//_duckVol = _player.volume;
//_player.setVolume(_duckVol - 0.4 > 0 ? _duckVol - 0.4 : 0.0);
}
void unDuck() {
//TODO: Confirm I need to do this manually, it looks like audioplayers already does this
print("Unduck requested");
//_player.setVolume(_duckVol);
}
@override @override
Future<void> play() async { Future<void> play() async {
if (await startAudioSession()) { if (await startAudioSession()) {

Binary file not shown.

Before

Width:  |  Height:  |  Size: 48 KiB

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.7 KiB

After

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 881 B

After

Width:  |  Height:  |  Size: 851 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.4 KiB

After

Width:  |  Height:  |  Size: 4.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 19 KiB

After

Width:  |  Height:  |  Size: 8.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.0 KiB

After

Width:  |  Height:  |  Size: 1.8 KiB

View File

@@ -16,7 +16,7 @@ publish_to: 'none' # Remove this line if you wish to publish to pub.dev
# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
# In Windows, build-name is used as the major, minor, and patch parts # In Windows, build-name is used as the major, minor, and patch parts
# of the product and file versions while build-number is used as the build suffix. # of the product and file versions while build-number is used as the build suffix.
version: 1.0.0+1 version: 1.0.1
environment: environment:
sdk: ^3.5.1 sdk: ^3.5.1
@@ -66,9 +66,12 @@ flutter:
uses-material-design: true uses-material-design: true
# To add assets to your application, add an assets section, like this: # To add assets to your application, add an assets section, like this:
# assets: assets:
# - images/a_dot_burr.jpeg # - images/a_dot_burr.jpeg
# - images/a_dot_ham.jpeg # - images/a_dot_ham.jpeg
- assets/images/app-background.jpg
- assets/images/app-background2.jpg
- assets/images/app-background3.jpg
# An image asset can refer to one or more resolution-specific "variants", see # An image asset can refer to one or more resolution-specific "variants", see
# https://flutter.dev/to/resolution-aware-images # https://flutter.dev/to/resolution-aware-images

Binary file not shown.

Before

Width:  |  Height:  |  Size: 881 B

After

Width:  |  Height:  |  Size: 851 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.6 KiB

After

Width:  |  Height:  |  Size: 4.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 19 KiB

After

Width:  |  Height:  |  Size: 8.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.6 KiB

After

Width:  |  Height:  |  Size: 4.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 19 KiB

After

Width:  |  Height:  |  Size: 8.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.6 KiB

After

Width:  |  Height:  |  Size: 4.2 KiB