private async Task ReadFromFile()
        {
            Log(Type.Event, "Started ReadFromFile method");

            #region UI Variables
            ImageView          savedView          = FindViewById <ImageView>(Resource.Id.savedView);
            TextView           infoTxt            = FindViewById <TextView>(Resource.Id.infoTxt);
            ProgressBar        lyricsLoadingWheel = FindViewById <ProgressBar>(Resource.Id.lyricsLoadingWheel);
            ImageButton        fabMore            = FindViewById <ImageButton>(Resource.Id.fabMore);
            SwipeRefreshLayout refreshLayout      = FindViewById <SwipeRefreshLayout>(Resource.Id.swipeRefreshLayout);
            #endregion

            songInfo = await Database.ReadLyrics(songInfo.Normal.Id);

            UpdateSong(songInfo, true, true, imagesOnDisk: true);

            RunOnUiThread(() =>
            {
                lyricsLoadingWheel.Visibility = ViewStates.Gone;
                fabMore.Visibility            = ViewStates.Visible;
                savedView.Visibility          = ViewStates.Visible;
                infoTxt.Visibility            = ViewStates.Visible;

                refreshLayout.Refreshing = false;
            });

            shouldCheck = true;
            Log(Type.Info, "Done reading from file!");
            Analytics.TrackEvent("Finished reading song from file", new Dictionary <string, string> {
                { "SongID", songInfo.Normal.Id.ToString() }
            });
        }
        protected override async void OnResume()
        {
            base.OnResume();
            Log(Type.Info, "OnResume started");

            bool fromNotification = Intent.HasExtra("NotificationSong");

            if (fromNotification)
            {
                Log(Type.Event, "Attempting to load song from notification");
                Analytics.TrackEvent("Opening song from notification", new Dictionary <string, string> {
                    { "NotificationSong", JsonConvert.SerializeObject(notificationSong) }
                });

                notificationSong = JsonConvert.DeserializeObject <SongBundle>(Intent.GetStringExtra("NotificationSong") !);

                NotificationManagerCompat ntfManager = NotificationManagerCompat.From(this);
                ntfManager.Cancel(NotificationId);

                songInfo        = notificationSong;
                previousNtfSong = notificationSong;

                shouldCheck    = false;
                nowPlayingMode = true;
                LoadSong();
            }
        }
Exemple #3
0
        private async Task OpenInMainActivity(SongBundle song)
        {
            Intent intent = new Intent(this, typeof(MainActivity)).SetFlags(ActivityFlags.ReorderToFront);

            intent.PutExtra("SavedSong", JsonConvert.SerializeObject(song));
            StartActivityForResult(intent, 1);
        }
Exemple #4
0
        private void CreateNotification(SongBundle song)
        {
            Log(Type.Info, "Creating notification");

            Intent info = new Intent(Application.Context, typeof(MainActivity));

            info.PutExtra("NotificationSong", JsonConvert.SerializeObject(song));

            TaskStackBuilder stackBuilder = TaskStackBuilder.Create(Application.Context);

            stackBuilder.AddParentStack(Java.Lang.Class.FromType(typeof(MainActivity)));
            stackBuilder.AddNextIntent(info);

            PendingIntent resultIntent = stackBuilder.GetPendingIntent(0, (int)PendingIntentFlags.UpdateCurrent);

            NotificationCompat.Builder builder = new NotificationCompat.Builder(this, ChannelId)
                                                 .SetAutoCancel(true)
                                                 .SetContentTitle(Resources?.GetString(Resource.String.app_name))
                                                 .SetContentText(song.Normal.Artist + " - " + song.Normal.Title)
                                                 .SetSmallIcon(Resource.Drawable.ic_stat_name)
                                                 .SetContentIntent(resultIntent)
                                                 .SetPriority(-1);

            ntfManager = NotificationManagerCompat.From(Application.Context);
            ntfManager.Notify(NotificationId, builder.Build());
            Log(Type.Event, "Notification made!");
        }
Exemple #5
0
        public static async Task <SongBundle> ReadLyrics(int id)
        {
            SongBundle song = await GetSongFromTable(id);

            string path = Path.Combine(Globals.ApplicationPath, Globals.SavedLyricsLocation + song.Normal.Id);

            //songInfo.Normal is already loaded (from SavedLyrics activity), load lyrics and images from disk
            //Load songInfo.Romanized lyrics if songInfo.Romanized lyrics were saved
            StreamReader sr = File.OpenText(path + Globals.LyricsExtension);

            song.Normal.Lyrics = await sr.ReadToEndAsync();

            if (song.Romanized != null)
            {
                sr.Dispose();
                sr = File.OpenText(path + Globals.RomanizedExtension);

                song.Romanized.Lyrics = await sr.ReadToEndAsync();
            }

            Logging.Log(Logging.Type.Event, "Read lyrics from file");
            sr.Dispose(); //Dispose/close manually since we're not using "using"

            return(song);
        }
Exemple #6
0
        public static async Task <string> GetSongLyrics(SongBundle song)
        {
            HtmlWeb      web = new HtmlWeb();
            HtmlDocument doc = await web.LoadFromWebAsync("https://genius.com" + song.Normal.Path);

            Log(Logging.Type.Processing, "Parsing HTML...");
            return(await HtmlParsing.ParseHtml(doc));
        }
        protected override void OnStop()
        {
            base.OnStop();

            Log(Type.Info, "OnStop started");
            notificationSong = new SongBundle();
            previousNtfSong  = notificationSong;
        }
        private async Task ShowSongDetails()
        {
            songInfo = await Genius.GetSongDetails(songInfo);

            UpdateSong(songInfo, true, true);
            Log(Type.Info, "Finished getting info from Genius");
            Analytics.TrackEvent("Finished getting info from Genius", new Dictionary <string, string> {
                { "SongID", songInfo.Normal.Id.ToString() }
            });
        }
        private async void CheckIfSongIsPlaying()
        {
            if (!shouldCheck || !MiscTools.IsInForeground())
            {
                return;
            }
            if (notificationSong.Normal.Id == previousNtfSong.Normal.Id)
            {
                return;
            }

            Log(Type.Event, "Song playing is different, updating...");

            nowPlayingMode  = true;
            songInfo        = notificationSong;
            previousNtfSong = notificationSong;

            bool autoUpdate = Prefs.GetBoolean("auto_update_page", false);

            if (autoUpdate && nowPlayingMode)
            {
                shouldCheck = false;
                LoadSong();
            }
            else if (nowPlayingMode)
            {
                shouldCheck = false;

                Android.Views.Animations.Animation anim = Animations.BlinkingAnimation(700, 3);
                npTxt.StartAnimation(anim);
                Log(Type.Event, "Playing animation on npTxt");
            }
            else if (!nowPlayingMode)
            {
                shouldCheck = false;

                Android.Views.Animations.Animation anim = Animations.BlinkingImageAnimation(500, 4);
                shineView.Visibility = ViewStates.Visible;
                shineView.StartAnimation(anim);
                Log(Type.Event, "Playing animation on shineView");
            }
        }
Exemple #10
0
        private async void SearchResults_ItemClick(object sender, AdapterView.ItemClickEventArgs e)
        {
            if (welcomeView != null)
            {
                dynamicLayout.RemoveView(welcomeView);
                welcomeView = null;

                InflateSong();
            }

            RunOnUiThread(() =>
            {
                dynamicLayout.Visibility = ViewStates.Visible;
            });

            #region UI Variables
            ProgressBar lyricsLoadingWheel = FindViewById <ProgressBar>(Resource.Id.lyricsLoadingWheel);
            ListView    searchResults      = FindViewById <ListView>(Resource.Id.searchResults);
            #endregion

            imm.HideSoftInputFromWindow(searchTxt.WindowToken, 0);
            nowPlayingMode = false;
            ClearLabels();

            songInfo ??= new SongBundle();
            songInfo = resultsToView.ElementAt(e.Position);

            Log(Type.Action, $"Attempting to display song at search position {e.Position}.");
            Analytics.TrackEvent("Attempting to display song from search", new Dictionary <string, string> {
                { "SongID", songInfo.Normal.Id.ToString() },
                { "ListPosition", e.Position.ToString() }
            });

            RunOnUiThread(() =>
            {
                lyricsLoadingWheel.Visibility = ViewStates.Visible;
                searchResults.Visibility      = ViewStates.Gone;
            });

            LoadSong();
        }
Exemple #11
0
        protected override async void OnNewIntent(Intent intent)
        {
            base.OnNewIntent(intent);

            //This should be called when a notification is opened, but that's not happening
            //Probably because it's not a new intent from a loaded activity, but a new one, you dumb ass

            if (intent.HasExtra("SavedSong"))
            {
                SongBundle saved = JsonConvert.DeserializeObject <SongBundle>(intent.GetStringExtra("SavedSong") ?? Resources.GetString(Resource.String.lyricsErrorOcurred));
                songInfo = saved;

                Log(Type.Event, "Received SavedSongs intent, loading song from disk");
                Analytics.TrackEvent("Received SavedSongs intent", new Dictionary <string, string> {
                    { "SongID", saved.Normal.Id.ToString() }
                });

                LoadSong();
            }

            Log(Type.Info, "OnNewIntent started");
        }
Exemple #12
0
        public static async Task <SongBundle> GetSongDetails(SongBundle song)
        {
            Log(Logging.Type.Info, "Starting GetSongDetails operation");
            string results = await HttpRequests.GetRequest(GeniusApiUrl + song.Normal.ApiPath, GeniusAuthHeader);

            JObject parsed = JObject.Parse(results);

            parsed = (JObject)parsed["response"]?["song"]; //Change root to song

            Song fromJson = new Song
            {
                Title   = (string)parsed?.SelectToken("title") ?? "",
                Artist  = (string)parsed?.SelectToken("primary_artist.name") ?? "",
                Album   = (string)parsed?.SelectToken("album.name") ?? "",
                Header  = (string)parsed?.SelectToken("header_image_url") ?? "",
                Cover   = (string)parsed?.SelectToken("song_art_image_url") ?? "",
                ApiPath = (string)parsed?.SelectToken("api_path") ?? "",
                Path    = (string)parsed?.SelectToken("path") ?? ""
            };

            song.Normal = fromJson;

            if (parsed != null && parsed["featured_artists"].HasValues)
            {
                IList <JToken> parsedList = parsed["featured_artists"].Children().ToList();

                song.Normal.FeaturedArtist = "feat. ";
                foreach (JToken artist in parsedList)
                {
                    if (song.Normal.FeaturedArtist == "feat. ")
                    {
                        song.Normal.FeaturedArtist += artist["name"]?.ToString();
                    }
                    else
                    {
                        song.Normal.FeaturedArtist += ", " + artist["name"];
                    }
                }

                Log(Logging.Type.Processing, "Added featured artists to song");
            }
            else
            {
                song.Normal.FeaturedArtist = "";
            }

            //Execute all Japanese transliteration tasks at once
            if (Prefs.GetBoolean("auto_romanize_details", true) && song.Normal.Title.ContainsJapanese() || song.Normal.Artist.ContainsJapanese() || song.Normal.Album.ContainsJapanese())
            {
                Task <string> awaitTitle  = song.Normal.Title.StripJapanese();
                Task <string> awaitArtist = song.Normal.Artist.StripJapanese();
                Task <string> awaitAlbum  = song.Normal.Album.StripJapanese();

                await Task.WhenAll(awaitTitle, awaitArtist, awaitAlbum);

                RomanizedSong romanized = new RomanizedSong();
                // This snippet is the same in GetAndShowLyrics
                song.Romanized ??= romanized;

                romanized.Title  = await awaitTitle;
                romanized.Artist = await awaitArtist;
                romanized.Album  = await awaitAlbum;

                romanized.Id          = song.Normal.Id;
                song.Romanized        = romanized;
                song.Normal.Romanized = true;

                Log(Logging.Type.Event, "Romanized song info with ID " + song.Normal.Id);
                Analytics.TrackEvent("Romanized song info", new Dictionary <string, string> {
                    { "SongID", song.Normal.Id.ToString() }
                });
            }
            else
            {
                song.Romanized = null;
            }

            return(song);
        }
Exemple #13
0
        private async void UpdateSong(SongBundle song,
                                      bool updateImages,
                                      bool updateDetails,
                                      bool imagesOnDisk = false)
        {
            Log(Type.Info, "Started UpdateSong method for ID " + song.Normal.Id);

            #region UI Variables
            TextView songLyrics = FindViewById <TextView>(Resource.Id.songLyrics);
            TextView songTitle  = FindViewById <TextView>(Resource.Id.songTitle);
            TextView songArtist = FindViewById <TextView>(Resource.Id.songArtist);
            TextView songAlbum  = FindViewById <TextView>(Resource.Id.songAlbum);
            TextView songFeat   = FindViewById <TextView>(Resource.Id.songFeat);
            #endregion

            RunOnUiThread(() =>
            {
                Song toShow = song.Normal;
                if (song.Normal.Romanized && song.Romanized != null && Prefs.GetBoolean("auto_romanize_details", false))
                {
                    Log(Type.Processing, $"Song with ID {songInfo.Normal.Id} has romanization data, using it for display");
                    toShow = (Song)song.Romanized;
                }

                if (!string.IsNullOrEmpty(song.Normal.Lyrics))
                {
                    bool romanizedIsValid = songInfo.Romanized != null && !string.IsNullOrEmpty(songInfo.Romanized.Lyrics) && Prefs.GetBoolean("auto_romanize", false);
                    string lyricsToShow   = romanizedIsValid
                        ? songInfo.Romanized.Lyrics
                        : songInfo.Normal.Lyrics;

                    songLyrics.TextFormatted = Build.VERSION.SdkInt >= BuildVersionCodes.N
                        ? Html.FromHtml(lyricsToShow, FromHtmlOptions.ModeCompact)
                        #pragma warning disable 618
                        : Html.FromHtml(lyricsToShow);
                        #pragma warning restore 618
                }

                if (updateDetails)
                {
                    songTitle.Text  = toShow.Title;
                    songArtist.Text = toShow.Artist;
                    songAlbum.Text  = toShow.Album;

                    if (string.IsNullOrEmpty(toShow.FeaturedArtist) || string.IsNullOrWhiteSpace(toShow.FeaturedArtist))
                    {
                        songFeat.Visibility = ViewStates.Gone;
                    }
                    else
                    {
                        songFeat.Visibility = ViewStates.Visible;
                        songFeat.Text       = toShow.FeaturedArtist;
                    }
                }

                Log(Type.Processing, "Updated labels");
            });

            if (updateImages) //TODO: Add timer to retry after enough time with images not updated
            {
                ImageButton coverView  = FindViewById <ImageButton>(Resource.Id.coverView);
                ImageView   headerView = FindViewById <ImageView>(Resource.Id.headerView);
                ImageView   searchView = FindViewById <ImageView>(Resource.Id.searchView);

                if (imagesOnDisk)
                {
                    string coverPath  = Path.Combine(ApplicationPath + "/" + SavedImagesLocation, song.Normal.Id + CoverSuffix);
                    string headerPath = Path.Combine(ApplicationPath + "/" + SavedImagesLocation, song.Normal.Id + HeaderSuffix);

                    RunOnUiThread(() =>
                    {
                        ImageService.Instance.LoadFile(coverPath)
                        .Transform(new RoundedTransformation(CoverRadius))
                        .Into(coverView);

                        if (File.Exists(headerPath))
                        {
                            ImageService.Instance.LoadFile(headerPath)
                            .Transform(new BlurredTransformation(HeaderBlur))
                            .Into(headerView);
                            ImageService.Instance.LoadFile(headerPath)
                            .Transform(new CropTransformation(3, 0, 0))
                            .Transform(new BlurredTransformation(SearchBlur))
                            .Transform(new BlurredTransformation(SearchBlur))
                            .Into(searchView);
                        }
                        else
                        {
                            ImageService.Instance.LoadFile(coverPath)
                            .Transform(new BlurredTransformation(HeaderBlur))
                            .Into(headerView);
                            ImageService.Instance.LoadFile(coverPath)
                            .Transform(new CropTransformation(3, 0, 0))
                            .Transform(new BlurredTransformation(SearchBlur))
                            .Transform(new BlurredTransformation(SearchBlur))
                            .Into(searchView);
                        }
                    });

                    Log(Type.Processing, "Updated images from disk");
                }
                else
                {
                    RunOnUiThread(() =>
                    {
                        ImageService.Instance.LoadUrl(song.Normal.Cover)
                        .Transform(new RoundedTransformation(CoverRadius))
                        .Into(coverView);
                        ImageService.Instance.LoadUrl(song.Normal.Header)
                        .Transform(new BlurredTransformation(HeaderBlur))
                        .Into(headerView);
                        ImageService.Instance.LoadUrl(song.Normal.Header)
                        .Transform(new CropTransformation(3, 0, 0))
                        .Transform(new BlurredTransformation(SearchBlur))
                        .Transform(new BlurredTransformation(SearchBlur))
                        .Into(searchView);
                    });

                    Log(Type.Processing, "Updated images from the internet");
                }
            }
        }
Exemple #14
0
        private bool nonGrouped; //TODO: Add persistency to grouping option

        #region Standard Activity Shit
        protected override async void OnCreate(Bundle savedInstanceState)
        {
            base.OnCreate(savedInstanceState);
            SetContentView(Resource.Layout.main_saved);
            CrossCurrentActivity.Current.Activity = this; //don't remove this, permission stuff needs it

            #region UI Variables
            DrawerLayout drawer    = FindViewById <DrawerLayout>(Resource.Id.drawer_layout);
            ImageButton  drawerBtn = FindViewById <ImageButton>(Resource.Id.drawerBtn);

            NavigationView navigationView = FindViewById <NavigationView>(Resource.Id.nav_view);

            ExpandableListView savedList           = FindViewById <ExpandableListView>(Resource.Id.savedList);
            ImageButton        selectGroupingBtn   = FindViewById <ImageButton>(Resource.Id.selectGroupingBtn);
            ListView           savedListNonGrouped = FindViewById <ListView>(Resource.Id.savedListNonGrouped);
            #endregion

            navigationView.NavigationItemSelected += NavigationView_NavigationViewSelected;
            drawerBtn.Click += delegate
            {
                drawer.OpenDrawer(navigationView);
            };

            selectGroupingBtn.Click += async delegate
            {
                if (!nonGrouped)
                {
                    nonGrouped                     = true;
                    savedList.Visibility           = ViewStates.Gone;
                    savedListNonGrouped.Visibility = ViewStates.Visible;
                    selectGroupingBtn.SetImageDrawable(GetDrawable(Resource.Drawable.ic_ungrouped));
                    await ShowSavedSongs();
                }
                else
                {
                    nonGrouped                     = false;
                    savedList.Visibility           = ViewStates.Visible;
                    savedListNonGrouped.Visibility = ViewStates.Gone;
                    selectGroupingBtn.SetImageDrawable(GetDrawable(Resource.Drawable.ic_grouped));
                    await ShowSavedSongs();
                }
            };

            savedList.ChildClick += async delegate(object sender, ExpandableListView.ChildClickEventArgs e)
            {
                SongBundle selection = artistSongs.ElementAt(e.GroupPosition).Value[e.ChildPosition];

                Log(Type.Action, "Clicked on item from grouped list");
                Analytics.TrackEvent("Clicked on item from non-grouped list", new Dictionary <string, string> {
                    { "SongID", selection.Normal.Id.ToString() }
                });

                await OpenInMainActivity(selection);
            };

            savedListNonGrouped.ItemClick += async delegate(object sender, AdapterView.ItemClickEventArgs e)
            {
                SongBundle selection = allSongs[e.Position];

                Log(Type.Action, "Clicked on item from non-grouped list");
                Analytics.TrackEvent("Clicked on item from non-grouped list", new Dictionary <string, string> {
                    { "SongID", selection.Normal.Id.ToString() }
                });

                await OpenInMainActivity(selection);
            };
        }
Exemple #15
0
        // Writes a song to the saved lyrics database.
        // Returns true if successful.
        //TODO: Add ability to return an error, song already saved or saved successfully messages
        public static async Task <bool> WriteInfoAndLyrics(SongBundle song)
        {
            await MiscTools.CheckAndCreateAppFolders();

            InitializeTables();
            db = await ReadDatabaseFile(DbPath);

            rdb = await ReadRomanizedDatabaseFile(RomanizedDbPath);

            try
            {
                if (await GetSongFromTable(song.Normal.Id) == null)
                {
                    // Write lyrics to file
                    string filepath = Path.Combine(LyricsPath, song.Normal.Id + Globals.LyricsExtension);
                    File.WriteAllText(filepath, song.Normal.Lyrics);

                    if (song.Romanized != null)
                    {
                        string romanizedFilepath = Path.Combine(LyricsPath, song.Normal.Id + Globals.RomanizedExtension);
                        File.WriteAllText(romanizedFilepath, song.Romanized.Lyrics);

                        song.Normal.Romanized = true;

                        rdb.Rows.Add(
                            song.Romanized.Id,
                            song.Romanized.Title,
                            song.Romanized.Artist,
                            song.Romanized.Album,
                            song.Romanized.FeaturedArtist);
                        rdb.WriteXml(RomanizedDbPath);
                    }

                    await WriteImages(song.Normal);

                    db.Rows.Add(
                        song.Normal.Id,
                        song.Normal.Title,
                        song.Normal.Artist,
                        song.Normal.Album,
                        song.Normal.FeaturedArtist,
                        song.Normal.Cover,
                        song.Normal.Header,
                        song.Normal.Romanized,
                        song.Normal.ApiPath,
                        song.Normal.Path);
                    db.WriteXml(DbPath);

                    Logging.Log(Logging.Type.Event, $"Wrote song {song.Normal.Id} to file");
                    Analytics.TrackEvent("Wrote song to file", new Dictionary <string, string> {
                        { "SongID", song.Normal.Id.ToString() },
                        { "DBSize", db.Rows.Count.ToString() },
                        { "RomanizedDBSize", rdb.Rows.Count.ToString() }
                    });
                    return(true);
                }
                else
                {
                    return(false);
                }
            }
            catch (IOException ex)
            {
                Crashes.TrackError(ex, new Dictionary <string, string> {
                    { "SongID", song.Normal.Id.ToString() },
                    { "Exception", ex.ToString() }
                });
                Logging.Log(Logging.Type.Error, "Exception while writing lyrics to disk!\n" + ex);

                return(false);
            }
            catch (NullReferenceException ex)
            {
                Crashes.TrackError(ex, new Dictionary <string, string> {
                    { "SongID", song.Normal.Id.ToString() },
                    { "Exception", ex.ToString() }
                });
                Logging.Log(Logging.Type.Error, "NullReferenceException while writing lyrics to disk! Reload song and try again.\n" + ex);

                return(false);
            }
            catch (Exception ex)
            {
                Crashes.TrackError(ex, new Dictionary <string, string> {
                    { "SongID", song.Normal.Id.ToString() },
                    { "Exception", ex.ToString() }
                });
                Logging.Log(Logging.Type.Error, "Unkown error while writing song to disk!\n" + ex);

                return(false);
            }
        }