mirror of
https://github.com/KRTirtho/spotube.git
synced 2025-09-13 16:05:18 +00:00
Infinite Scorll added
CategoryCard no-title bug fix shuffle support added
This commit is contained in:
parent
799e13c376
commit
0ef44709fa
@ -7,7 +7,7 @@ import 'package:spotube/provider/SpotifyDI.dart';
|
||||
|
||||
class CategoryCard extends StatefulWidget {
|
||||
final Category category;
|
||||
CategoryCard(this.category);
|
||||
const CategoryCard(this.category, {Key? key}) : super(key: key);
|
||||
|
||||
@override
|
||||
_CategoryCardState createState() => _CategoryCardState();
|
||||
@ -16,8 +16,7 @@ class CategoryCard extends StatefulWidget {
|
||||
class _CategoryCardState extends State<CategoryCard> {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Container(
|
||||
child: Column(
|
||||
return Column(
|
||||
children: [
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
@ -33,12 +32,15 @@ class _CategoryCardState extends State<CategoryCard> {
|
||||
Navigator.of(context).push(
|
||||
MaterialPageRoute(
|
||||
builder: (context) {
|
||||
return PlaylistGenreView(widget.category.id!);
|
||||
return PlaylistGenreView(
|
||||
widget.category.id!,
|
||||
widget.category.name!,
|
||||
);
|
||||
},
|
||||
),
|
||||
);
|
||||
},
|
||||
child: Text("See all"),
|
||||
child: const Text("See all"),
|
||||
)
|
||||
],
|
||||
),
|
||||
@ -51,10 +53,10 @@ class _CategoryCardState extends State<CategoryCard> {
|
||||
.getPage(4, 0),
|
||||
builder: (context, snapshot) {
|
||||
if (snapshot.hasError) {
|
||||
return Center(child: Text("Error occurred"));
|
||||
return const Center(child: Text("Error occurred"));
|
||||
}
|
||||
if (!snapshot.hasData) {
|
||||
return Center(child: Text("Loading.."));
|
||||
return const Center(child: Text("Loading.."));
|
||||
}
|
||||
return Wrap(
|
||||
spacing: 20,
|
||||
@ -65,7 +67,6 @@ class _CategoryCardState extends State<CategoryCard> {
|
||||
}),
|
||||
)
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,5 @@
|
||||
import 'package:flutter/material.dart' hide Page;
|
||||
import 'package:infinite_scroll_pagination/infinite_scroll_pagination.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import 'package:shared_preferences/shared_preferences.dart';
|
||||
import 'package:spotify/spotify.dart';
|
||||
@ -10,11 +11,16 @@ import 'package:spotube/provider/Auth.dart';
|
||||
import 'package:spotube/provider/SpotifyDI.dart';
|
||||
|
||||
class Home extends StatefulWidget {
|
||||
const Home({Key? key}) : super(key: key);
|
||||
|
||||
@override
|
||||
_HomeState createState() => _HomeState();
|
||||
}
|
||||
|
||||
class _HomeState extends State<Home> {
|
||||
final PagingController<int, Category> _pagingController =
|
||||
PagingController(firstPageKey: 0);
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
@ -39,12 +45,35 @@ class _HomeState extends State<Home> {
|
||||
);
|
||||
}
|
||||
}
|
||||
_pagingController.addPageRequestListener((pageKey) async {
|
||||
try {
|
||||
SpotifyDI data = context.read<SpotifyDI>();
|
||||
Page<Category> categories = await data.spotifyApi.categories
|
||||
.list(country: "US")
|
||||
.getPage(15, pageKey);
|
||||
|
||||
if (categories.isLast && categories.items != null) {
|
||||
_pagingController.appendLastPage(categories.items!.toList());
|
||||
} else if (categories.items != null) {
|
||||
_pagingController.appendPage(
|
||||
categories.items!.toList(), categories.nextOffset);
|
||||
}
|
||||
} catch (e) {
|
||||
_pagingController.error = e;
|
||||
}
|
||||
});
|
||||
} catch (e) {
|
||||
print("[login state error]: $e");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_pagingController.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
Auth authProvider = Provider.of<Auth>(context);
|
||||
@ -53,8 +82,7 @@ class _HomeState extends State<Home> {
|
||||
}
|
||||
|
||||
return Scaffold(
|
||||
body: Container(
|
||||
child: Column(
|
||||
body: Column(
|
||||
children: [
|
||||
// Side Tab Bar
|
||||
Expanded(
|
||||
@ -74,9 +102,8 @@ class _HomeState extends State<Home> {
|
||||
children: [
|
||||
ListTile(
|
||||
title: Text("Spotube",
|
||||
style: Theme.of(context)
|
||||
.textTheme
|
||||
.headline4),
|
||||
style:
|
||||
Theme.of(context).textTheme.headline4),
|
||||
leading:
|
||||
const Icon(Icons.miscellaneous_services),
|
||||
),
|
||||
@ -115,31 +142,17 @@ class _HomeState extends State<Home> {
|
||||
),
|
||||
// contents of the spotify
|
||||
Consumer<SpotifyDI>(builder: (_, data, __) {
|
||||
return FutureBuilder<Page<Category>>(
|
||||
future: data.spotifyApi.categories
|
||||
.list(country: "US")
|
||||
.getPage(10, 0),
|
||||
builder: (context, snapshot) {
|
||||
if (snapshot.hasError) {
|
||||
return const Center(child: Text("Error occured"));
|
||||
}
|
||||
if (!snapshot.hasData) {
|
||||
return const Center(child: Text("Loading"));
|
||||
}
|
||||
List<Category> categories =
|
||||
snapshot.data!.items!.toList();
|
||||
return Expanded(
|
||||
child: Scrollbar(
|
||||
isAlwaysShown: true,
|
||||
child: ListView.builder(
|
||||
itemCount: categories.length,
|
||||
itemBuilder: (context, index) {
|
||||
return CategoryCard(categories[index]);
|
||||
child: PagedListView(
|
||||
pagingController: _pagingController,
|
||||
builderDelegate: PagedChildBuilderDelegate<Category>(
|
||||
itemBuilder: (context, item, index) {
|
||||
return CategoryCard(item);
|
||||
},
|
||||
),
|
||||
)),
|
||||
),
|
||||
);
|
||||
});
|
||||
}),
|
||||
],
|
||||
),
|
||||
@ -148,7 +161,6 @@ class _HomeState extends State<Home> {
|
||||
const player.Player()
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,7 @@
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:cached_network_image/cached_network_image.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:spotube/components/PlayerControls.dart';
|
||||
import 'package:spotube/provider/Playback.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
@ -18,8 +20,7 @@ class _PlayerState extends State<Player> {
|
||||
late MPVPlayer player;
|
||||
|
||||
bool _isPlaying = false;
|
||||
String? _mediaTitle;
|
||||
String? _mediaArtists;
|
||||
bool _shuffled = false;
|
||||
double _duration = 0;
|
||||
|
||||
String? _currentPlaylistId;
|
||||
@ -45,8 +46,10 @@ class _PlayerState extends State<Player> {
|
||||
_volume = volume / 100;
|
||||
});
|
||||
} catch (e) {
|
||||
if (kDebugMode) {
|
||||
print("[PLAYER]: $e");
|
||||
}
|
||||
}
|
||||
})();
|
||||
|
||||
player.on(MPVEvents.paused, null, (ev, context) {
|
||||
@ -65,20 +68,27 @@ class _PlayerState extends State<Player> {
|
||||
player.on(MPVEvents.status, null, (ev, _) async {
|
||||
Map data = ev.eventData as Map;
|
||||
Playback playback = context.read<Playback>();
|
||||
print("[DATA]: $data");
|
||||
if (data["property"] == "media-title" && data["value"] != null) {
|
||||
var containsYtdl = (data["value"] as String).contains("ytsearch:");
|
||||
if (containsYtdl) {
|
||||
var props = (data["value"] as String).split("-");
|
||||
var mediaTitle = props.last.trim();
|
||||
var mediaArtists = props.first.split("ytsearch:").last.trim();
|
||||
setState(() {
|
||||
_isPlaying = true;
|
||||
_mediaTitle = props.last.replaceAll(
|
||||
RegExp(
|
||||
"(official|video|lyric|[(){}\\[\\]\\|])",
|
||||
caseSensitive: false,
|
||||
),
|
||||
"",
|
||||
);
|
||||
_mediaArtists = props.first;
|
||||
});
|
||||
|
||||
var matchedTracks = playback.currentPlaylist?.tracks.where(
|
||||
(track) {
|
||||
return track.name == mediaTitle &&
|
||||
artistsToString(track.artists ?? []) == mediaArtists;
|
||||
},
|
||||
) ??
|
||||
[];
|
||||
if (matchedTracks.isNotEmpty) {
|
||||
playback.setCurrentTrack = matchedTracks.first;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (data["property"] == "duration" && data["value"] != null) {
|
||||
setState(() {
|
||||
@ -90,30 +100,6 @@ class _PlayerState extends State<Player> {
|
||||
super.initState();
|
||||
}
|
||||
|
||||
@override
|
||||
void didChangeDependencies() {
|
||||
super.didChangeDependencies();
|
||||
Playback playback = context.read<Playback>();
|
||||
|
||||
String? prevTrackName = playback.currentTrack?.name;
|
||||
String prevTrackArtists =
|
||||
artistsToString(playback.currentTrack?.artists ?? []);
|
||||
|
||||
if (playback.currentPlaylist != null &&
|
||||
playback.currentPlaylist!.tracks.isNotEmpty &&
|
||||
prevTrackName != _mediaTitle &&
|
||||
prevTrackArtists != _mediaArtists) {
|
||||
var tracks = playback.currentPlaylist?.tracks.where((track) {
|
||||
return _mediaTitle == track.name! &&
|
||||
artistsToString(track.artists ?? []) == _mediaTitle;
|
||||
}) ??
|
||||
[];
|
||||
if (tracks.isNotEmpty) {
|
||||
playback.setCurrentTrack = tracks.first;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
player.removeAllByEvent(MPVEvents.paused);
|
||||
@ -134,7 +120,6 @@ class _PlayerState extends State<Player> {
|
||||
File file = File(playlistPath);
|
||||
var newPlaylist = playlistToStr(playlist);
|
||||
|
||||
print("😃PLAYING PLAYLIST😃");
|
||||
if (!await file.exists()) {
|
||||
await file.create();
|
||||
}
|
||||
@ -144,6 +129,7 @@ class _PlayerState extends State<Player> {
|
||||
await player.loadPlaylist(playlistPath);
|
||||
setState(() {
|
||||
_currentPlaylistId = playlist.id;
|
||||
_shuffled = false;
|
||||
});
|
||||
}
|
||||
}
|
||||
@ -162,21 +148,30 @@ class _PlayerState extends State<Player> {
|
||||
playPlaylist(playback.currentPlaylist!);
|
||||
}
|
||||
|
||||
String? albumArt = playback.currentTrack?.album?.images?.last.url;
|
||||
|
||||
return Material(
|
||||
type: MaterialType.transparency,
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
||||
children: [
|
||||
if (albumArt != null)
|
||||
CachedNetworkImage(
|
||||
imageUrl: albumArt,
|
||||
maxHeightDiskCache: 50,
|
||||
maxWidthDiskCache: 50,
|
||||
),
|
||||
// title of the currently playing track
|
||||
Flexible(
|
||||
flex: 1,
|
||||
child: Column(
|
||||
children: [
|
||||
Text(
|
||||
_mediaTitle ?? "Not playing",
|
||||
playback.currentTrack?.name ?? "Not playing",
|
||||
style: const TextStyle(fontWeight: FontWeight.bold),
|
||||
),
|
||||
Text(_mediaArtists ?? "")
|
||||
Text(
|
||||
artistsToString(playback.currentTrack?.artists ?? []))
|
||||
],
|
||||
),
|
||||
),
|
||||
@ -187,13 +182,28 @@ class _PlayerState extends State<Player> {
|
||||
player: player,
|
||||
isPlaying: _isPlaying,
|
||||
duration: _duration,
|
||||
shuffled: _shuffled,
|
||||
onShuffle: () {
|
||||
if (!_shuffled) {
|
||||
player.shuffle().then(
|
||||
(value) => setState(() {
|
||||
_shuffled = true;
|
||||
}),
|
||||
);
|
||||
} else {
|
||||
player.unshuffle().then(
|
||||
(value) => setState(() {
|
||||
_shuffled = false;
|
||||
}),
|
||||
);
|
||||
}
|
||||
},
|
||||
onStop: () {
|
||||
setState(() {
|
||||
_isPlaying = false;
|
||||
_currentPlaylistId = null;
|
||||
_mediaArtists = null;
|
||||
_mediaTitle = null;
|
||||
_duration = 0;
|
||||
_shuffled = false;
|
||||
});
|
||||
playback.reset();
|
||||
},
|
||||
|
@ -5,11 +5,15 @@ class PlayerControls extends StatefulWidget {
|
||||
final MPVPlayer player;
|
||||
final bool isPlaying;
|
||||
final double duration;
|
||||
final bool shuffled;
|
||||
final Function? onStop;
|
||||
final Function? onShuffle;
|
||||
const PlayerControls({
|
||||
required this.player,
|
||||
required this.isPlaying,
|
||||
required this.duration,
|
||||
required this.shuffled,
|
||||
this.onShuffle,
|
||||
this.onStop,
|
||||
Key? key,
|
||||
}) : super(key: key);
|
||||
@ -86,8 +90,10 @@ class _PlayerControlsState extends State<PlayerControls> {
|
||||
children: [
|
||||
IconButton(
|
||||
icon: const Icon(Icons.shuffle_rounded),
|
||||
onPressed: () async {
|
||||
await widget.player.shuffle();
|
||||
color:
|
||||
widget.shuffled ? Theme.of(context).primaryColor : null,
|
||||
onPressed: () {
|
||||
widget.onShuffle?.call();
|
||||
}),
|
||||
IconButton(
|
||||
icon: const Icon(Icons.skip_previous_rounded),
|
||||
|
@ -5,8 +5,10 @@ import 'package:spotube/components/PlaylistCard.dart';
|
||||
import 'package:spotube/provider/SpotifyDI.dart';
|
||||
|
||||
class PlaylistGenreView extends StatefulWidget {
|
||||
String genre_id;
|
||||
PlaylistGenreView(this.genre_id);
|
||||
final String genreId;
|
||||
final String genreName;
|
||||
const PlaylistGenreView(this.genreId, this.genreName, {Key? key})
|
||||
: super(key: key);
|
||||
@override
|
||||
_PlaylistGenreViewState createState() => _PlaylistGenreViewState();
|
||||
}
|
||||
@ -15,17 +17,16 @@ class _PlaylistGenreViewState extends State<PlaylistGenreView> {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
body: Container(
|
||||
child: Column(
|
||||
body: Column(
|
||||
children: [
|
||||
Row(
|
||||
// mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
BackButton(),
|
||||
const BackButton(),
|
||||
// genre name
|
||||
Expanded(
|
||||
child: Text(
|
||||
"Genre Name",
|
||||
widget.genreName,
|
||||
style: Theme.of(context).textTheme.headline4,
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
@ -37,14 +38,14 @@ class _PlaylistGenreViewState extends State<PlaylistGenreView> {
|
||||
child: SingleChildScrollView(
|
||||
child: FutureBuilder<Iterable<PlaylistSimple>>(
|
||||
future: data.spotifyApi.playlists
|
||||
.getByCategoryId(widget.genre_id)
|
||||
.getByCategoryId(widget.genreId)
|
||||
.all(),
|
||||
builder: (context, snapshot) {
|
||||
if (snapshot.hasError) {
|
||||
return Center(child: Text("Error occurred"));
|
||||
return const Center(child: Text("Error occurred"));
|
||||
}
|
||||
if (!snapshot.hasData) {
|
||||
return Center(child: Text("Loading.."));
|
||||
return const Center(child: Text("Loading.."));
|
||||
}
|
||||
return Wrap(
|
||||
children: snapshot.data!
|
||||
@ -62,7 +63,6 @@ class _PlaylistGenreViewState extends State<PlaylistGenreView> {
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -6,8 +6,8 @@ import 'package:spotube/components/TrackButton.dart';
|
||||
import 'package:spotube/provider/SpotifyDI.dart';
|
||||
|
||||
class PlaylistView extends StatefulWidget {
|
||||
PlaylistSimple playlist;
|
||||
PlaylistView(this.playlist);
|
||||
final PlaylistSimple playlist;
|
||||
const PlaylistView(this.playlist, {Key? key}) : super(key: key);
|
||||
@override
|
||||
_PlaylistViewState createState() => _PlaylistViewState();
|
||||
}
|
||||
@ -18,19 +18,12 @@ class _PlaylistViewState extends State<PlaylistView> {
|
||||
Playback playback = context.read<Playback>();
|
||||
return Consumer<SpotifyDI>(builder: (_, data, __) {
|
||||
return Scaffold(
|
||||
body: Container(
|
||||
child: FutureBuilder<Iterable<Track>>(
|
||||
body: FutureBuilder<Iterable<Track>>(
|
||||
future: data.spotifyApi.playlists
|
||||
.getTracksByPlaylistId(widget.playlist.id)
|
||||
.all(),
|
||||
builder: (context, snapshot) {
|
||||
if (snapshot.hasError) {
|
||||
return const Center(child: const Text("Error occurred"));
|
||||
}
|
||||
if (!snapshot.hasData) {
|
||||
return const Center(child: const Text("Loading.."));
|
||||
}
|
||||
List<Track> tracks = snapshot.data!.toList();
|
||||
List<Track> tracks = snapshot.data?.toList() ?? [];
|
||||
return Column(
|
||||
children: [
|
||||
Row(
|
||||
@ -43,24 +36,42 @@ class _PlaylistViewState extends State<PlaylistView> {
|
||||
onPressed: () {},
|
||||
),
|
||||
// play playlist
|
||||
IconButton(
|
||||
icon: const Icon(Icons.play_arrow_rounded),
|
||||
onPressed: () {
|
||||
playback.setCurrentPlaylist = CurrentPlaylist(
|
||||
tracks: tracks,
|
||||
id: widget.playlist.id!,
|
||||
name: widget.playlist.name!,
|
||||
thumbnail: widget.playlist.images![0].url!,
|
||||
);
|
||||
},
|
||||
Consumer<Playback>(builder: (context, playback, widget) {
|
||||
var isPlaylistPlaying = playback.currentPlaylist?.id ==
|
||||
this.widget.playlist.id;
|
||||
return IconButton(
|
||||
icon: Icon(
|
||||
isPlaylistPlaying
|
||||
? Icons.stop_rounded
|
||||
: Icons.play_arrow_rounded,
|
||||
),
|
||||
onPressed: snapshot.hasData
|
||||
? () {
|
||||
if (!isPlaylistPlaying) {
|
||||
playback.setCurrentPlaylist =
|
||||
CurrentPlaylist(
|
||||
tracks: tracks,
|
||||
id: this.widget.playlist.id!,
|
||||
name: this.widget.playlist.name!,
|
||||
thumbnail:
|
||||
this.widget.playlist.images![0].url!,
|
||||
);
|
||||
}
|
||||
}
|
||||
: null,
|
||||
);
|
||||
}),
|
||||
],
|
||||
),
|
||||
Center(
|
||||
child: Text(widget.playlist.name!,
|
||||
style: Theme.of(context).textTheme.headline4),
|
||||
),
|
||||
Expanded(
|
||||
snapshot.hasError
|
||||
? const Center(child: Text("Error occurred"))
|
||||
: !snapshot.hasData
|
||||
? const Center(child: Text("Loading.."))
|
||||
: Expanded(
|
||||
child: Scrollbar(
|
||||
isAlwaysShown: true,
|
||||
child: ListView.builder(
|
||||
@ -82,14 +93,16 @@ class _PlaylistViewState extends State<PlaylistView> {
|
||||
Track track = tracks[index - 1];
|
||||
return TrackButton(
|
||||
index: (index - 1).toString(),
|
||||
thumbnail_url: track.album?.images?.last.url ??
|
||||
thumbnail_url: track
|
||||
.album?.images?.last.url ??
|
||||
"https://i.scdn.co/image/ab67616d00001e02b993cba8ff7d0a8e9ee18d46",
|
||||
trackName: track.name!,
|
||||
artists:
|
||||
track.artists!.map((e) => e.name!).toList(),
|
||||
artists: track.artists!
|
||||
.map((e) => e.name!)
|
||||
.toList(),
|
||||
album: track.album!.name!,
|
||||
playback_time:
|
||||
track.duration!.inMinutes.toString(),
|
||||
playback_time: track.duration!.inMinutes
|
||||
.toString(),
|
||||
onTap: () {},
|
||||
);
|
||||
}),
|
||||
@ -98,7 +111,6 @@ class _PlaylistViewState extends State<PlaylistView> {
|
||||
],
|
||||
);
|
||||
}),
|
||||
),
|
||||
);
|
||||
});
|
||||
}
|
||||
|
@ -30,7 +30,7 @@ class _TrackButtonState extends State<TrackButton> {
|
||||
child: InkWell(
|
||||
onTap: widget.onTap,
|
||||
child: Ink(
|
||||
padding: EdgeInsets.all(10),
|
||||
padding: const EdgeInsets.all(10),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
@ -38,16 +38,16 @@ class _TrackButtonState extends State<TrackButton> {
|
||||
children: [
|
||||
Text(
|
||||
widget.index,
|
||||
style: TextStyle(fontSize: 20),
|
||||
style: const TextStyle(fontSize: 20),
|
||||
),
|
||||
SizedBox(width: 15),
|
||||
const SizedBox(width: 15),
|
||||
if (widget.thumbnail_url != null)
|
||||
CachedNetworkImage(
|
||||
imageUrl: widget.thumbnail_url!,
|
||||
maxHeightDiskCache: 50,
|
||||
maxWidthDiskCache: 50,
|
||||
),
|
||||
SizedBox(width: 15),
|
||||
const SizedBox(width: 15),
|
||||
Container(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
@ -55,7 +55,7 @@ class _TrackButtonState extends State<TrackButton> {
|
||||
Text(
|
||||
widget.trackName,
|
||||
textAlign: TextAlign.justify,
|
||||
style: TextStyle(
|
||||
style: const TextStyle(
|
||||
fontWeight: FontWeight.bold, fontSize: 17),
|
||||
),
|
||||
Text(widget.artists.join(", "))
|
||||
@ -64,9 +64,9 @@ class _TrackButtonState extends State<TrackButton> {
|
||||
),
|
||||
],
|
||||
),
|
||||
SizedBox(width: 15),
|
||||
const SizedBox(width: 15),
|
||||
Text(widget.album),
|
||||
SizedBox(width: 15),
|
||||
const SizedBox(width: 15),
|
||||
Text(widget.playback_time)
|
||||
],
|
||||
),
|
||||
|
@ -29,8 +29,8 @@ class MyApp extends StatelessWidget {
|
||||
theme: ThemeData(
|
||||
primaryColor: Colors.greenAccent[400],
|
||||
primarySwatch: Colors.green,
|
||||
buttonTheme: ButtonThemeData(
|
||||
buttonColor: Colors.greenAccent[400],
|
||||
buttonTheme: const ButtonThemeData(
|
||||
buttonColor: Colors.green,
|
||||
),
|
||||
),
|
||||
home: Home(),
|
||||
|
14
pubspec.lock
14
pubspec.lock
@ -177,6 +177,13 @@ packages:
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "4.0.0"
|
||||
infinite_scroll_pagination:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: infinite_scroll_pagination
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "3.1.0"
|
||||
js:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -406,6 +413,13 @@ packages:
|
||||
description: flutter
|
||||
source: sdk
|
||||
version: "0.0.99"
|
||||
sliver_tools:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: sliver_tools
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "0.2.5"
|
||||
source_span:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -44,6 +44,7 @@ dependencies:
|
||||
youtube_explode_dart: ^1.10.8
|
||||
mpv_dart:
|
||||
path: ../mpv_dart
|
||||
infinite_scroll_pagination: ^3.1.0
|
||||
|
||||
dev_dependencies:
|
||||
flutter_test:
|
||||
|
Loading…
Reference in New Issue
Block a user