Skip to content

Commit

Permalink
Merge branch 'release/v0.8.0'
Browse files Browse the repository at this point in the history
  • Loading branch information
JuanM04 committed Jan 23, 2020
2 parents 2c7008e + 15344c8 commit 493c599
Show file tree
Hide file tree
Showing 34 changed files with 1,067 additions and 602 deletions.
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@
# is commented out by default.
#.vscode/

# Secrets
google-services.json

# Flutter/Dart/Pub related
**/doc/api/
.dart_tool/
Expand Down
12 changes: 8 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
![Banner](images/Banner.png)

![Version](https://img.shields.io/github/v/release/JuanM04/animu?style=flat-square)
![License](https://img.shields.io/github/license/JuanM04/animu?style=flat-square)
![Flutter](https://img.shields.io/static/v1?label=Flutter&message=v1.12&logo=flutter&color=02569B&style=flat-square)
Expand All @@ -10,16 +11,19 @@ Animú es una app para ver anime sin complicaciones. Funciona con los servidores

### ¿Cómo funciona?

Animú consta de la app (hecha en Flutter) y un servidor en ZEIT Now.

Este último sirve para saltarse la seguridad de Cloudflare al momento de pedirle información a AnimeFLV. Esto se hace porque Animú usa Web Scraping, que básicamente es descargar el HTML y sacar el contenido de ahí (en vez de pedirlo a una API). Usa `web/api/get-cloudflare-id.ts` solamente para "fingir un PC real" y luego sigue haciendo peticiones desde la app. La página web está en `web/`.
Animú consta de la app (hecha en Flutter), [AnimeFLV GraphQL](https://github.com/JuanM04/animeflv-graphql) y una función en ZEIT Now.

Para el modo Transmitir, se usa la API proveida por VLC 3+. Más información [aquí](https://wiki.videolan.org/VLC_HTTP_requests/).
Todos los datos son guardados con [HiveDB](https://github.com/hivedb/hive). Para el modo Transmitir, se usa la API proveida por VLC 3+. Más información [aquí](https://wiki.videolan.org/VLC_HTTP_requests/).

### ¿Por qué está todo en inglés?

Tengo problemas, no me peguen.

## Setup

1. Agregar `android/app/google-services.json` de Firebase.
2. Ejecturar `flutter pub get`.

## To-do

- Animaciones
Expand Down
2 changes: 2 additions & 0 deletions android/app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ if (flutterVersionName == null) {
apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle"
apply plugin: 'com.google.gms.google-services'

android {
compileSdkVersion 28
Expand Down Expand Up @@ -78,4 +79,5 @@ dependencies {
testImplementation 'junit:junit:4.12'
androidTestImplementation 'androidx.test:runner:1.1.1'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.1'
implementation 'com.google.firebase:firebase-analytics:17.2.0'
}
1 change: 1 addition & 0 deletions android/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ buildscript {
dependencies {
classpath 'com.android.tools.build:gradle:3.3.2'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
classpath 'com.google.gms:google-services:4.3.2'
}
}

Expand Down
12 changes: 10 additions & 2 deletions lib/main.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,11 @@ import 'package:animu/screens/browse.dart';
import 'package:animu/screens/saved_animes.dart';
import 'package:animu/screens/settings/settings.dart';
import 'package:animu/screens/splash_screen/splash_screen.dart';
import 'package:animu/services/requests.dart';
import 'package:animu/services/backup.dart';
import 'package:animu/utils/notifiers.dart';
import 'package:firebase_analytics/firebase_analytics.dart';
import 'package:firebase_analytics/observer.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:provider/provider.dart';
Expand All @@ -27,10 +30,12 @@ class MyApp extends StatelessWidget {

final primaryColor = Color(0xFFBF3030); // Strawberry Red

final analytics = FirebaseAnalytics();

return MultiProvider(
providers: [
ChangeNotifierProvider<VLCNotifier>.value(value: VLCNotifier()),
Provider<RequestsService>.value(value: RequestsService()),
StreamProvider<FirebaseUser>.value(value: BackupService.userStream),
],
child: MaterialApp(
title: 'Animú',
Expand Down Expand Up @@ -65,6 +70,9 @@ class MyApp extends StatelessWidget {
'/home': (context) => TabsWrapper(),
},
initialRoute: '/',
navigatorObservers: [
FirebaseAnalyticsObserver(analytics: analytics),
],
),
);
}
Expand Down
79 changes: 34 additions & 45 deletions lib/screens/anime/anime.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,11 @@ import 'package:animu/screens/anime/episode_list.dart';
import 'package:animu/services/requests.dart';
import 'package:animu/utils/models.dart';
import 'package:animu/services/anime_database.dart';
import 'package:animu/utils/helpers.dart';
import 'package:animu/utils/watching_states.dart';
import 'package:animu/widgets/dialog_button.dart';
import 'package:animu/widgets/spinner.dart';
import 'package:auto_size_text/auto_size_text.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:provider/provider.dart';

import 'main_button.dart';

Expand All @@ -19,35 +16,26 @@ class AnimeScreen extends StatefulWidget {
}

class _AnimeScreenState extends State<AnimeScreen> {
RequestsService requestsService;
Anime anime;
List<Episode> episodes;
bool loading = true;

double positionFromBottom(int n) => n * 50.00 + (n + 1) * 20;

void getAnimeDBData() async {
dynamic dbAnime = await AnimeDatabaseService().getAnimeById(anime.id);
dynamic dbAnime = AnimeDatabaseService.getAnimeById(anime.id);
if (dbAnime != null) setState(() => anime = dbAnime);
}

void getEpisodes() async {
List response = await requestsService.getEpisodes(anime: anime);

if (mounted)
setState(() {
episodes = new List<Episode>.from(
response.map((list) => Episode(id: list[1], n: list[0])).toList(),
);
loading = false;
});
episodes = await RequestsService.getEpisodes(anime);
if (mounted) setState(() => loading = false);
}

@override
Widget build(BuildContext context) {
if (anime == null) {
anime = ModalRoute.of(context).settings.arguments;
requestsService = Provider.of<RequestsService>(context);
getAnimeDBData();
}
if (episodes == null) getEpisodes();
Expand All @@ -61,28 +49,10 @@ class _AnimeScreenState extends State<AnimeScreen> {
child: Stack(
overflow: Overflow.visible,
children: <Widget>[
Image.network(
getImageURL(ImageURLType.cover, anime: anime),
Image.memory(
anime.cover,
fit: BoxFit.cover,
width: MediaQuery.of(context).size.width,
headers: requestsService.headers,
),
Positioned(
bottom: 5,
left: 10,
width: MediaQuery.of(context).size.width * 0.8,
child: AutoSizeText(
anime.name,
style: TextStyle(
fontWeight: FontWeight.w800,
fontSize: 28,
letterSpacing: 1,
height: 1.25,
shadows: [
Shadow(color: Colors.black87, blurRadius: 10),
],
),
),
),
Positioned(
bottom: positionFromBottom(1),
Expand All @@ -104,11 +74,11 @@ class _AnimeScreenState extends State<AnimeScreen> {
style: TextStyle(color: Colors.white),
),
selected: anime.watchingState == state,
onSelected: (changed) async {
onSelected: (changed) {
if (!changed) return;
anime.watchingState = state;
await AnimeDatabaseService()
.updateAnime(anime);
AnimeDatabaseService.updateAnime(
anime);
setState(
() => Navigator.pop(context));
},
Expand All @@ -119,10 +89,9 @@ class _AnimeScreenState extends State<AnimeScreen> {
if (anime.watchingState != null)
DialogButton(
label: 'Eliminar estado',
onPressed: () async {
onPressed: () {
anime.watchingState = null;
await AnimeDatabaseService()
.updateAnime(anime);
AnimeDatabaseService.updateAnime(anime);
setState(() => Navigator.pop(context));
},
),
Expand All @@ -147,9 +116,9 @@ class _AnimeScreenState extends State<AnimeScreen> {
child: MainButton(
backgroundColor: Theme.of(context).primaryColor,
child: IconButton(
onPressed: () async {
onPressed: () {
anime.favorite = !anime.favorite;
await AnimeDatabaseService().updateAnime(anime);
AnimeDatabaseService.updateAnime(anime);
setState(() {});
},
icon: Icon(anime.favorite
Expand All @@ -166,18 +135,38 @@ class _AnimeScreenState extends State<AnimeScreen> {
],
),
),
Padding(
padding: EdgeInsets.symmetric(horizontal: 10, vertical: 10),
child: Row(
children: <Widget>[
SizedBox(
width: MediaQuery.of(context).size.width * .7,
child: Text(
anime.name,
textAlign: TextAlign.left,
style: TextStyle(
fontWeight: FontWeight.w800,
fontSize: 24,
letterSpacing: 1,
height: 1.25,
),
),
),
],
),
),
Expanded(
child: !loading
? EpisodeList(
anime: anime,
episodes: episodes,
seenUnseen: (episode) async {
seenUnseen: (episode) {
if (anime.episodesSeen == null) anime.episodesSeen = [];
if (anime.episodesSeen.contains(episode.n))
anime.episodesSeen.remove(episode.n);
else
anime.episodesSeen.add(episode.n);
await AnimeDatabaseService().updateAnime(anime);
AnimeDatabaseService.updateAnime(anime);
HapticFeedback.vibrate();
setState(() {});
},
Expand Down
13 changes: 1 addition & 12 deletions lib/screens/anime/episode_list.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,6 @@ import 'dart:math';

import 'package:animu/screens/cast_player/cast_player.dart';
import 'package:animu/screens/player/player.dart';
import 'package:animu/services/requests.dart';
import 'package:animu/utils/helpers.dart';
import 'package:animu/utils/models.dart';
import 'package:animu/utils/notifiers.dart';
import 'package:flutter/material.dart';
Expand Down Expand Up @@ -36,8 +34,6 @@ class EpisodeList extends StatelessWidget {

@override
Widget build(BuildContext context) {
final requestsService = Provider.of<RequestsService>(context);

return Column(
children: <Widget>[
Expanded(
Expand All @@ -56,14 +52,7 @@ class EpisodeList extends StatelessWidget {
children: <Widget>[
ClipRRect(
borderRadius: BorderRadius.circular(5),
child: Image.network(
getImageURL(
ImageURLType.thumbnail,
anime: anime,
episode: episodes[i],
),
headers: requestsService.headers,
),
child: Image.memory(episodes[i].thumbnail),
),
Align(
alignment: Alignment.center,
Expand Down
20 changes: 2 additions & 18 deletions lib/screens/browse.dart
Original file line number Diff line number Diff line change
Expand Up @@ -4,36 +4,22 @@ import 'package:animu/widgets/search_bar.dart';
import 'package:animu/utils/models.dart';
import 'package:animu/widgets/spinner.dart';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';

class Browse extends StatefulWidget {
@override
_BrowseState createState() => _BrowseState();
}

class _BrowseState extends State<Browse> {
RequestsService requestsService;
List<Anime> animes;
bool loading = false;

void getAnimes(String query) async {
setState(() => loading = true);

List response = await requestsService.searchAnimes(query);
animes = await RequestsService.searchAnimes(query);

if (mounted)
setState(() {
animes = new List<Anime>.from(response
.map(
(map) => Anime(
id: int.parse(map['id']),
name: map['title'],
slug: map['slug'],
),
)
.toList());
loading = false;
});
if (mounted) setState(() => loading = false);
}

Widget bigContent() {
Expand All @@ -56,8 +42,6 @@ class _BrowseState extends State<Browse> {

@override
Widget build(BuildContext context) {
requestsService = Provider.of<RequestsService>(context);

return Scaffold(
body: SafeArea(
child: Padding(
Expand Down
8 changes: 1 addition & 7 deletions lib/screens/cast_player/cast_player.dart
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import 'dart:async';

import 'package:animu/services/requests.dart';
import 'package:animu/services/sources.dart';
import 'package:animu/widgets/previous_next.dart';
import 'package:animu/utils/models.dart';
Expand All @@ -19,7 +18,6 @@ class CastPlayer extends StatefulWidget {
class _CastPlayerState extends State<CastPlayer> {
PlayerData data;
VLCNotifier vlc;
RequestsService requestsService;

Timer ticker;
dynamic tickerData;
Expand All @@ -30,10 +28,7 @@ class _CastPlayerState extends State<CastPlayer> {
}

void initPlayer() async {
final url = await getEpisodeURLFromData(
requestsService: requestsService,
data: data,
);
final url = await getEpisodeURLFromData(data);
if (!mounted) return;
if (url == null) return initPlayer();
tickerData = await vlc.send('in_play', input: url);
Expand Down Expand Up @@ -61,7 +56,6 @@ class _CastPlayerState extends State<CastPlayer> {
if (data == null) {
data = ModalRoute.of(context).settings.arguments;
vlc = Provider.of<VLCNotifier>(context);
requestsService = Provider.of<RequestsService>(context);
initPlayer();
}

Expand Down
Loading

0 comments on commit 493c599

Please sign in to comment.