Skip to content

Commit

Permalink
Podcast description now occupies a maximum amount of space when viewi…
Browse files Browse the repository at this point in the history
…ng podcast details. If the descrioption requires more space, a expand icon appears allowing the user the expand/contract the details.
  • Loading branch information
amugofjava authored and amugofjava committed Jan 2, 2023
1 parent 72ba45b commit 98789a6
Show file tree
Hide file tree
Showing 12 changed files with 154 additions and 37 deletions.
4 changes: 2 additions & 2 deletions lib/core/environment.dart
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@ const userAgentAppString = String.fromEnvironment('USER_AGENT', defaultValue: ''
class Environment {
static const _applicationName = 'Anytime';
static const _applicationUrl = 'https://github.com/amugofjava/anytime_podcast_player';
static const _projectVersion = '1.2.1';
static const _build = '74';
static const _projectVersion = '1.2.2';
static const _build = '75';

static var _agentString = userAgentAppString;

Expand Down
2 changes: 1 addition & 1 deletion lib/main.dart
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ void main() async {
/// The Let's Encrypt CA expired on at the end of September 2021. This causes problems when trying to
/// fetch feeds secured with the CA. Older Android devices, 7.0 and before, cannot be updated with the
/// latest CA so this routine manually sets up the updated LE CA when running on Android v7.0 or earlier.
void setupCertificateAuthority() async {
Future<void> setupCertificateAuthority() async {
if (Platform.isAndroid) {
DeviceInfoPlugin deviceInfo = DeviceInfoPlugin();
AndroidDeviceInfo androidInfo = await deviceInfo.androidInfo;
Expand Down
2 changes: 1 addition & 1 deletion lib/services/download/download_manager.dart
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ class DownloadProgress {
}

abstract class DownloadManager {
Future<String> enqueTask(String url, String downloadPath, String fileName);
Future<String> enqueueTask(String url, String downloadPath, String fileName);
Stream<DownloadProgress> get downloadProgress;
void dispose();
}
3 changes: 2 additions & 1 deletion lib/services/download/mobile_download_manager.dart
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ class MobileDownloaderManager implements DownloadManager {
}

@override
Future<String> enqueTask(String url, String downloadPath, String fileName) async {
Future<String> enqueueTask(String url, String downloadPath, String fileName) async {
return await FlutterDownloader.enqueue(
url: url,
savedDir: downloadPath,
Expand Down Expand Up @@ -108,6 +108,7 @@ class MobileDownloaderManager implements DownloadManager {
}
}

@pragma('vm:entry-point')
static void downloadCallback(String id, DownloadTaskStatus status, int progress) {
final send = IsolateNameServer.lookupPortByName('downloader_send_port');

Expand Down
2 changes: 1 addition & 1 deletion lib/services/download/mobile_download_service.dart
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ class MobileDownloadService extends DownloadService {

log.fine('Download episode (${episode?.title}) $filename to $downloadPath/$filename');

final taskId = await downloadManager.enqueTask(episode.contentUrl, downloadPath, filename);
final taskId = await downloadManager.enqueueTask(episode.contentUrl, downloadPath, filename);

// Update the episode with download data
episode.filepath = episodePath;
Expand Down
4 changes: 2 additions & 2 deletions lib/ui/anytime_podcast_app.dart
Original file line number Diff line number Diff line change
Expand Up @@ -605,7 +605,7 @@ class _AnytimeHomePageState extends State<AnytimeHomePage> with WidgetsBindingOb

class TitleWidget extends StatelessWidget {
final TextStyle _titleTheme1 = theme.textTheme.bodyText2.copyWith(
color: Colors.orange[700],
color: Color.fromARGB(255, 255, 153, 0),
fontWeight: FontWeight.bold,
fontFamily: 'MontserratRegular',
fontSize: 18,
Expand All @@ -628,7 +628,7 @@ class TitleWidget extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.only(left: 4.0),
padding: const EdgeInsets.only(left: 2.0),
child: Row(
children: <Widget>[
Text(
Expand Down
13 changes: 12 additions & 1 deletion lib/ui/podcast/dot_decoration.dart
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,9 @@ class _DotDecorationPainter extends BoxPainter {

@override
void paint(Canvas canvas, Offset offset, ImageConfiguration configuration) {
const double pillWidth = 8.0;
const double pillHeight = 3.0;

final center = configuration.size.center(offset);
final height = configuration.size.height;

Expand All @@ -31,6 +34,14 @@ class _DotDecorationPainter extends BoxPainter {
paint.color = decoration.colour;
paint.style = PaintingStyle.fill;

canvas.drawCircle(newOffset, 4, paint);
canvas.drawRRect(
RRect.fromLTRBR(
newOffset.dx - pillWidth,
newOffset.dy - pillHeight,
newOffset.dx + pillWidth,
newOffset.dy + pillHeight,
Radius.circular(12.0),
),
paint);
}
}
2 changes: 1 addition & 1 deletion lib/ui/podcast/player_transport_controls.dart
Original file line number Diff line number Diff line change
Expand Up @@ -173,7 +173,7 @@ class _AnimatedPlayButtonState extends State<AnimatedPlayButton> with SingleTick
style: TextButton.styleFrom(
shape: CircleBorder(side: BorderSide(color: Theme.of(context).highlightColor, width: 0.0)),
backgroundColor: Theme.of(context).brightness == Brightness.light ? Colors.orange : Colors.grey[800],
primary: Theme.of(context).brightness == Brightness.light ? Colors.orange : Colors.grey[800],
foregroundColor: Theme.of(context).brightness == Brightness.light ? Colors.orange : Colors.grey[800],
padding: const EdgeInsets.all(6.0),
),
onPressed: () {
Expand Down
129 changes: 117 additions & 12 deletions lib/ui/podcast/podcast_details.dart
Original file line number Diff line number Diff line change
Expand Up @@ -334,40 +334,93 @@ class PodcastHeaderImage extends StatelessWidget {
}
}

class PodcastTitle extends StatelessWidget {
class PodcastTitle extends StatefulWidget {
final Podcast podcast;

PodcastTitle(this.podcast);

@override
State<PodcastTitle> createState() => _PodcastTitleState();
}

class _PodcastTitleState extends State<PodcastTitle> {
final GlobalKey descriptionKey = GlobalKey();
final maxHeight = 100.0;
PodcastHtml description;
bool showOverflow = false;
bool expanded = false;

@override
Widget build(BuildContext context) {
final textTheme = Theme.of(context).textTheme;
final settings = Provider.of<SettingsBloc>(context).currentSettings;

return Padding(
padding: const EdgeInsets.fromLTRB(8.0, 16.0, 8.0, 0.0),
padding: const EdgeInsets.fromLTRB(8.0, 8.0, 8.0, 0.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Padding(
padding: const EdgeInsets.symmetric(horizontal: 8),
child: Text(podcast.title ?? '', style: textTheme.headline6),
Row(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Expanded(
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Padding(
padding: const EdgeInsets.fromLTRB(8.0, 8.0, 8.0, 2.0),
child: Text(widget.podcast.title ?? '', style: textTheme.headline6),
),
Padding(
padding: const EdgeInsets.fromLTRB(8, 0, 8, 8),
child: Text(widget.podcast.copyright ?? '', style: textTheme.caption),
),
],
),
),
Visibility(
visible: showOverflow,
child: expanded
? TextButton(
style: ButtonStyle(
visualDensity: VisualDensity.compact,
),
child: Icon(Icons.expand_less),
onPressed: () {
setState(() {
expanded = false;
});
},
)
: TextButton(
style: ButtonStyle(visualDensity: VisualDensity.compact),
child: Icon(Icons.expand_more),
onPressed: () {
setState(() {
expanded = true;
});
},
),
)
],
),
Padding(
padding: const EdgeInsets.fromLTRB(8, 4, 8, 8),
child: Text(podcast.copyright ?? '', style: textTheme.caption),
PodcastDescription(
key: descriptionKey,
content: description,
expanded: expanded,
),
PodcastHtml(content: podcast.description),
Padding(
padding: const EdgeInsets.only(left: 8.0, right: 8.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[
SubscriptionButton(podcast),
PodcastContextMenu(podcast),
SubscriptionButton(widget.podcast),
PodcastContextMenu(widget.podcast),
settings.showFunding
? FundingMenu(podcast.funding)
? FundingMenu(widget.podcast.funding)
: const SizedBox(
width: 0.0,
height: 0.0,
Expand All @@ -384,6 +437,58 @@ class PodcastTitle extends StatelessWidget {
),
);
}

@override
void initState() {
super.initState();

description = PodcastHtml(
content: widget.podcast.description,
);

WidgetsBinding.instance.addPostFrameCallback((timeStamp) {
print(descriptionKey.currentContext.size.height);

if (descriptionKey.currentContext.size.height == maxHeight) {
setState(() {
showOverflow = true;
});
}
});
}
}

/// This class wraps the description in an expandable box. This handles the
/// common case whereby the description is very long and, without this constraint,
/// would require the use to always scroll before reaching the podcast episodes.
///
/// TODO: Animate between the two states.
class PodcastDescription extends StatelessWidget {
final PodcastHtml content;
final bool expanded;
final maxHeight = 100.0;

const PodcastDescription({
Key key,
this.content,
this.expanded,
}) : super(key: key);
@override
Widget build(BuildContext context) {
return expanded
? content
: ConstrainedBox(
constraints: BoxConstraints.loose(Size(double.infinity, maxHeight)),
child: ShaderMask(
shaderCallback: LinearGradient(
colors: [Colors.white, Colors.white.withAlpha(0)],
begin: Alignment.topCenter,
end: Alignment.bottomCenter,
stops: [0.9, 1],
).createShader,
child: content),
);
}
}

class SubscriptionButton extends StatelessWidget {
Expand Down
8 changes: 4 additions & 4 deletions lib/ui/themes.dart
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import 'package:flutter/material.dart';
import 'package:flutter/services.dart';

final ThemeData _lightTheme = _buildLightTheme();
final ThemeData _darkTheme = _buildDarktheme();
final ThemeData _darkTheme = _buildDarkTheme();

ThemeData _buildLightTheme() {
final base = ThemeData.light();
Expand Down Expand Up @@ -66,12 +66,12 @@ ThemeData _buildLightTheme() {
actionTextColor: Colors.orange,
),
outlinedButtonTheme: OutlinedButtonThemeData(
style: OutlinedButton.styleFrom(primary: Colors.grey[800]),
style: OutlinedButton.styleFrom(foregroundColor: Colors.grey[800]),
),
);
}

ThemeData _buildDarktheme() {
ThemeData _buildDarkTheme() {
final base = ThemeData.dark();

return base.copyWith(
Expand Down Expand Up @@ -132,7 +132,7 @@ ThemeData _buildDarktheme() {
),
outlinedButtonTheme: OutlinedButtonThemeData(
style: OutlinedButton.styleFrom(
primary: Color(0xffffffff),
foregroundColor: Color(0xffffffff),
side: BorderSide(
color: Color(0xffffffff),
style: BorderStyle.solid,
Expand Down
12 changes: 6 additions & 6 deletions lib/ui/widgets/podcast_html.dart
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,9 @@ class PodcastHtml extends StatelessWidget {
final tagList = Html.tags;

PodcastHtml({
Key key,
@required this.content,
});
}) : super(key: key);

@override
Widget build(BuildContext context) {
Expand All @@ -26,11 +27,10 @@ class PodcastHtml extends StatelessWidget {
)
},
tagsList: tagList,
onLinkTap: (url, _, __, ___) =>
canLaunchUrl(Uri.parse(url)).then((value) => launchUrl(
Uri.parse(url),
mode: LaunchMode.externalApplication,
)),
onLinkTap: (url, _, __, ___) => canLaunchUrl(Uri.parse(url)).then((value) => launchUrl(
Uri.parse(url),
mode: LaunchMode.externalApplication,
)),
);
}
}
10 changes: 5 additions & 5 deletions pubspec.yaml
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
name: anytime
description: Anytime Podcast Player

version: 1.2.1+74
version: 1.2.2+75

environment:
sdk: ">=2.10.0 <3.0.0"
flutter: 3.0.0

dependencies:
auto_size_text: ^3.0.0
audio_service: ^0.18.8
audio_session: ^0.1.10
audio_service: ^0.18.9
audio_session: ^0.1.13
connectivity_plus: ^3.0.2
cupertino_icons: ^1.0.5
device_info_plus: ^4.0.0
Expand All @@ -19,14 +19,14 @@ dependencies:
file_picker: ^4.6.0
flutter_dialogs: ^3.0.0
flutter_downloader: ^1.9.1
flutter_html: ^3.0.0-alpha.5
flutter_html: ^3.0.0-alpha.6
flutter_html_svg: ^3.0.0-alpha.3
flutter_html_table: ^3.0.0-alpha.3
flutter_launcher_icons: ^0.11.0
flutter_spinkit: ^5.0.0
html: ^0.15.0
intl: ^0.17.0
just_audio: ^0.9.30
just_audio: ^0.9.31
logging: ^1.0.2
meta: ^1.7.0
mp3_info: ^0.2.0
Expand Down

0 comments on commit 98789a6

Please sign in to comment.