18 Commits
mvp2 ... v1

Author SHA1 Message Date
955b691ed6 updated for google play store / app store 2024-09-23 22:28:02 -04:00
fb03d06b0a stop playing when app swiped by user on android 2024-09-23 21:02:00 -04:00
d2173319b2 add comment for why no longer resume 2024-09-23 20:18:59 -04:00
f232324f11 add iOS specific about page 2024-09-23 20:18:50 -04:00
426c6b7567 load about from remote url 2024-09-23 20:10:08 -04:00
7e6aaf40c4 add loading indicator for better ux 2024-09-23 16:46:43 -04:00
bc30c9586e loading streaming url at runtime dynamically 2024-09-23 16:46:29 -04:00
36e13ecb50 changes for ios app store release 2024-09-20 10:29:24 -04:00
d08ce9172f regenerated icons for app store release 2024-09-20 10:02:29 -04:00
2cfddc0fe9 changed workflow to build debug appbundle 2024-09-19 22:13:04 -04:00
c2c919b55e changes for play store initial release 2024-09-19 21:59:20 -04:00
c3717042a1 regenerated icons 2024-09-19 21:18:23 -04:00
04873f1240 minor refactoring / cleaning 2024-09-19 20:49:12 -04:00
137f31c104 state from notification stop now works 2024-09-19 20:02:58 -04:00
0a9b0f7547 now with background images! 2024-09-18 21:36:43 -04:00
1a6ca9fa73 add demo link for web 2024-09-18 19:20:54 -04:00
4fc2c4bfa6 changed to push to production on cf pages 2024-09-18 18:29:51 -04:00
9070b70145 add cf pages deploy for web 2024-09-18 18:00:53 -04:00
64 changed files with 271 additions and 89 deletions

View File

@@ -37,7 +37,7 @@ jobs:
run: flutter build linux run: flutter build linux
- name: Build for Android - name: Build for Android
run: flutter build appbundle run: flutter build appbundle --debug
- name: Build for web - name: Build for web
run: flutter build web --no-web-resources-cdn --csp --web-renderer canvaskit run: flutter build web --no-web-resources-cdn --csp --web-renderer canvaskit
@@ -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

@@ -11,12 +11,12 @@ or to facilitate user input for internet radio sites.
This app has been designed to run across all platforms! This app has been designed to run across all platforms!
- Android - Android ([Google Play Store](https://play.google.com/store/apps/details?id=net.ything.radio.android))
- iOS - iOS (Requires [TestFlight](https://itunes.apple.com/us/app/testflight/id899247664?mt=8), contact info@ything.app for invitation)
- 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!
@@ -25,7 +25,5 @@ Want to have us modify this app for you? Reach out to info@ything.app
Coming Soon: Coming Soon:
- Apple App Store Live Demo! - Apple App Store Live Demo!
- Google Play Store Live Demo!
- Windows portable exe - Windows portable exe
- Web based live demo
- Screenshots / Demo Videos - Screenshots / Demo Videos

View File

@@ -5,6 +5,12 @@ plugins {
id "dev.flutter.flutter-gradle-plugin" id "dev.flutter.flutter-gradle-plugin"
} }
def keystoreProperties = new Properties()
def keystorePropertiesFile = rootProject.file('key.properties')
if (keystorePropertiesFile.exists()) {
keystoreProperties.load(new FileInputStream(keystorePropertiesFile))
}
android { android {
namespace = "net.ything.radio.android" namespace = "net.ything.radio.android"
//compileSdk = flutter.compileSdkVersion //compileSdk = flutter.compileSdkVersion
@@ -25,17 +31,27 @@ android {
applicationId = "net.ything.radio.android" applicationId = "net.ything.radio.android"
// You can update the following values to match your application needs. // You can update the following values to match your application needs.
// For more information, see: https://flutter.dev/to/review-gradle-config. // For more information, see: https://flutter.dev/to/review-gradle-config.
minSdk = flutter.minSdkVersion minSdk = 24
targetSdk = flutter.targetSdkVersion targetSdk = 34
versionCode = flutter.versionCode versionCode = 2
versionName = flutter.versionName versionName = "1.0.2"
} }
signingConfigs {
release {
keyAlias = keystoreProperties['keyAlias']
keyPassword = keystoreProperties['keyPassword']
storeFile = keystoreProperties['storeFile'] ? file(keystoreProperties['storeFile']) : null
storePassword = keystoreProperties['storePassword']
}
}
buildTypes { buildTypes {
release { release {
// TODO: Add your own signing config for the release build. // TODO: Add your own signing config for the release build.
// Signing with the debug keys for now, so `flutter run --release` works. // Signing with the debug keys for now, so `flutter run --release` works.
signingConfig = signingConfigs.debug signingConfig = signingConfigs.release
} }
} }
} }

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

View File

@@ -0,0 +1,4 @@
storePassword=
keyPassword=
keyAlias=
storeFile=

View File

@@ -0,0 +1,4 @@
https://docs.flutter.dev/deployment/android#signing-the-app
keytool -genkey -v -keystore ~/upload-keystore.jks -keyalg RSA -keysize 2048 -validity 10000 -alias upload

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

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

View File

@@ -1,6 +1,7 @@
flutter_launcher_icons: flutter_launcher_icons:
android: true android: true
ios: true ios: true
remove_alpha_ios: true
image_path: "assets/appicon/icon.png" image_path: "assets/appicon/icon.png"
min_sdk_android: 21 min_sdk_android: 21
adaptive_icon_background: "#FFA86A" adaptive_icon_background: "#FFA86A"

View File

@@ -40,5 +40,12 @@ end
post_install do |installer| post_install do |installer|
installer.pods_project.targets.each do |target| installer.pods_project.targets.each do |target|
flutter_additional_ios_build_settings(target) flutter_additional_ios_build_settings(target)
target.build_configurations.each do |config|
config.build_settings['GCC_PREPROCESSOR_DEFINITIONS'] ||= [
'$(inherited)',
'AUDIO_SESSION_MICROPHONE=0'
]
end
end end
end end

View File

@@ -49,6 +49,6 @@ SPEC CHECKSUMS:
sqflite: 673a0e54cc04b7d6dba8d24fb8095b31c3a99eec sqflite: 673a0e54cc04b7d6dba8d24fb8095b31c3a99eec
url_launcher_ios: 5334b05cef931de560670eeae103fd3e431ac3fe url_launcher_ios: 5334b05cef931de560670eeae103fd3e431ac3fe
PODFILE CHECKSUM: 819463e6a0290f5a72f145ba7cde16e8b6ef0796 PODFILE CHECKSUM: fe2316eacdf4337bc10b81b9cf460c6f69aee374
COCOAPODS: 1.15.2 COCOAPODS: 1.15.2

Binary file not shown.

Before

Width:  |  Height:  |  Size: 48 KiB

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 KiB

After

Width:  |  Height:  |  Size: 944 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

After

Width:  |  Height:  |  Size: 1.3 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: 1.3 KiB

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.9 KiB

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.3 KiB

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.0 KiB

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.6 KiB

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.7 KiB

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.5 KiB

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.8 KiB

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.6 KiB

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.6 KiB

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.5 KiB

After

Width:  |  Height:  |  Size: 3.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.1 KiB

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.0 KiB

After

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.1 KiB

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.1 KiB

After

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.3 KiB

After

Width:  |  Height:  |  Size: 3.5 KiB

View File

@@ -1,40 +1,29 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:ything_radio/SafeZone.dart'; import 'package:ything_radio/SafeZone.dart';
import 'Globals.dart';
class About extends StatelessWidget { class About extends StatelessWidget {
const About({super.key}); const About({super.key});
@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: 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 ' getAboutText(),
'multiple radio stations, a discovery platform, or to facilitate user input for ' textAlign: TextAlign.justify,
'internet radio sites.' ),
'\n\n'
'This app has been designed to run across all platforms!'
'\n\n'
'Android, iOS, MacOS, Windows, Linux, and Web!'
'\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

@@ -1,11 +1,55 @@
import 'dart:io' show Platform;
import 'package:audio_service/audio_service.dart'; import 'package:audio_service/audio_service.dart';
import 'package:audio_session/audio_session.dart'; import 'package:audio_session/audio_session.dart';
import 'package:audioplayers/audioplayers.dart';
import 'package:http/http.dart' as http;
import 'ListenHandler.dart'; import 'ListenHandler.dart';
late final ListenHandler _listenHandler; late final ListenHandler _listenHandler;
late final AudioSession _session; late final AudioSession _session;
const String _fallback =
"https://generic.ything.app/music/separation-185196.mp3";
final _urlSource = Uri.parse("https://generic.ything.app/music/player.url");
late final String _radioUrl;
Future<void> loadCurrentUrl() async {
final resp = await http.get(_urlSource);
if (resp.statusCode == 200) {
_radioUrl = resp.body.trim();
print('Loaded remote url');
} else {
_radioUrl = _fallback;
print('Request for current streaming url failed, using fallback url');
}
}
const String _fallbackAbout =
"Ything Radio is an internet radio streaming application.";
final _urlAbout =
Uri.parse("https://generic.ything.app/ything_radio/about.txt");
final _urlAboutIOS =
Uri.parse("https://generic.ything.app/ything_radio/about_ios.txt");
late final String _remoteAbout;
Future<void> loadAboutUrl() async {
final resp = await http.get(Platform.isIOS ? _urlAboutIOS : _urlAbout);
if (resp.statusCode == 200) {
_remoteAbout = resp.body;
print('Loaded remote about');
} else {
_remoteAbout = _fallbackAbout;
print('Request for remote about failed, using fallback about');
}
}
String getAboutText() => _remoteAbout;
Future<void> setupListenHandler() async { Future<void> setupListenHandler() async {
_listenHandler = await AudioService.init( _listenHandler = await AudioService.init(
builder: () => ListenHandler(), builder: () => ListenHandler(),
@@ -17,10 +61,44 @@ 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;
UrlSource getUrlSource() {
return UrlSource(_radioUrl, mimeType: "audio/mpeg");
}
Future<bool> startAudioSession() async { Future<bool> startAudioSession() async {
return await _session.setActive(true); return await _session.setActive(true);
} }

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,7 +36,7 @@ class _PlayControlsState extends State<PlayControls>
@override @override
bool get wantKeepAlive => true; bool get wantKeepAlive => true;
bool isPlaying = false; bool _isLoading = false;
final ListenHandler _listenHandler = getListenHandlder(); final ListenHandler _listenHandler = getListenHandlder();
@@ -37,14 +46,12 @@ 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()");
return;
}
setState(() { setState(() {
isPlaying = event.playing; //if state changed, we're no longer loading!
print("Updated playing state to $isPlaying"); //doesn't matter if we're playing or not!
_isLoading = false;
}); });
}); });
} }
@@ -56,48 +63,45 @@ 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 {
if (_isLoading) {
//skip doing anything else if we're still loading...
return;
}
await playPause();
setState(() { setState(() {
isPlaying = !isPlaying; if (!_listenHandler.isPlaying()) {
_isLoading = true;
}
}); });
}, },
child: SizedBox( child: SizedBox(
width: 100, width: 100,
height: 100, height: 100,
child: Icon( child: Icon(
isPlaying ? Icons.stop : Icons.play_arrow, _isLoading
? Icons.hourglass_empty
: _listenHandler.isPlaying()
? Icons.stop
: Icons.play_arrow,
color: Colors.white, color: Colors.white,
size: 50, size: 50,
), ),

View File

@@ -5,21 +5,68 @@ import 'package:ything_radio/Globals.dart';
class ListenHandler extends BaseAudioHandler { class ListenHandler extends BaseAudioHandler {
final _player = AudioPlayer(); final _player = AudioPlayer();
final UrlSource _radioSource = UrlSource( final UrlSource _radioSource = getUrlSource();
"https://generic.ything.app/music/separation-185196.mp3",
mimeType: "audio/mpeg");
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()) {
//setSource followed by resume does not work on Android or web
//play works everywhere though
_player.play(_radioSource, mode: PlayerMode.mediaPlayer); _player.play(_radioSource, mode: PlayerMode.mediaPlayer);
} }
} }
@@ -32,4 +79,11 @@ class ListenHandler extends BaseAudioHandler {
@override @override
Future<void> stop() => pause(); Future<void> stop() => pause();
//make appo stop playing when swiped away in task manager on Android
@override
Future<void> onTaskRemoved() async {
await stop();
return super.onTaskRemoved();
}
} }

View File

@@ -10,6 +10,7 @@ class YthingRadio extends StatelessWidget {
Widget build(BuildContext context) { Widget build(BuildContext context) {
return MaterialApp( return MaterialApp(
title: 'Ything Radio', title: 'Ything Radio',
debugShowCheckedModeBanner: false,
theme: ThemeData( theme: ThemeData(
colorScheme: ColorScheme.fromSeed( colorScheme: ColorScheme.fromSeed(
seedColor: Colors.orange, seedColor: Colors.orange,

View File

@@ -4,6 +4,8 @@ import 'Globals.dart';
import 'YthingRadio.dart'; import 'YthingRadio.dart';
Future<void> main() async { Future<void> main() async {
await loadCurrentUrl();
await loadAboutUrl();
await setupListenHandler(); await setupListenHandler();
runApp(const YthingRadio()); runApp(const YthingRadio());
} }

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

@@ -273,7 +273,7 @@ packages:
source: hosted source: hosted
version: "7.7.0" version: "7.7.0"
http: http:
dependency: transitive dependency: "direct main"
description: description:
name: http name: http
sha256: b9c29a161230ee03d3ccf545097fccd9b87a5264228c5d348202e0f0c28f9010 sha256: b9c29a161230ee03d3ccf545097fccd9b87a5264228c5d348202e0f0c28f9010

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.2
environment: environment:
sdk: ^3.5.1 sdk: ^3.5.1
@@ -40,6 +40,7 @@ dependencies:
flutter_tabler_icons: ^1.38.0 flutter_tabler_icons: ^1.38.0
audio_service: ^0.18.15 audio_service: ^0.18.15
audio_session: ^0.1.21 audio_session: ^0.1.21
http: ^1.2.2
dev_dependencies: dev_dependencies:
flutter_test: flutter_test:
@@ -66,9 +67,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