添加歌词显示功能

pull/1/head
jsyjst 7 years ago
parent eccd8b4301
commit 6c7b150b13

@ -0,0 +1,29 @@
<component name="ProjectCodeStyleConfiguration">
<code_scheme name="Project" version="173">
<Objective-C-extensions>
<file>
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Import" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Macro" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Typedef" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Enum" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Constant" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Global" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Struct" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="FunctionPredecl" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Function" />
</file>
<class>
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Property" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Synthesize" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="InitMethod" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="StaticMethod" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="InstanceMethod" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="DeallocMethod" />
</class>
<extensions>
<pair source="cpp" header="h" fileNamingConvention="NONE" />
<pair source="c" header="h" fileNamingConvention="NONE" />
</extensions>
</Objective-C-extensions>
</code_scheme>
</component>

@ -5,26 +5,37 @@
<option name="myDefaultNotNull" value="android.support.annotation.NonNull" />
<option name="myNullables">
<value>
<list size="4">
<list size="10">
<item index="0" class="java.lang.String" itemvalue="org.jetbrains.annotations.Nullable" />
<item index="1" class="java.lang.String" itemvalue="javax.annotation.Nullable" />
<item index="2" class="java.lang.String" itemvalue="edu.umd.cs.findbugs.annotations.Nullable" />
<item index="3" class="java.lang.String" itemvalue="android.support.annotation.Nullable" />
<item index="4" class="java.lang.String" itemvalue="javax.annotation.CheckForNull" />
<item index="5" class="java.lang.String" itemvalue="androidx.annotation.Nullable" />
<item index="6" class="java.lang.String" itemvalue="androidx.annotation.RecentlyNullable" />
<item index="7" class="java.lang.String" itemvalue="org.checkerframework.checker.nullness.qual.Nullable" />
<item index="8" class="java.lang.String" itemvalue="org.checkerframework.checker.nullness.compatqual.NullableDecl" />
<item index="9" class="java.lang.String" itemvalue="org.checkerframework.checker.nullness.compatqual.NullableType" />
</list>
</value>
</option>
<option name="myNotNulls">
<value>
<list size="4">
<list size="9">
<item index="0" class="java.lang.String" itemvalue="org.jetbrains.annotations.NotNull" />
<item index="1" class="java.lang.String" itemvalue="javax.annotation.Nonnull" />
<item index="2" class="java.lang.String" itemvalue="edu.umd.cs.findbugs.annotations.NonNull" />
<item index="3" class="java.lang.String" itemvalue="android.support.annotation.NonNull" />
<item index="4" class="java.lang.String" itemvalue="androidx.annotation.NonNull" />
<item index="5" class="java.lang.String" itemvalue="androidx.annotation.RecentlyNonNull" />
<item index="6" class="java.lang.String" itemvalue="org.checkerframework.checker.nullness.qual.NonNull" />
<item index="7" class="java.lang.String" itemvalue="org.checkerframework.checker.nullness.compatqual.NonNullDecl" />
<item index="8" class="java.lang.String" itemvalue="org.checkerframework.checker.nullness.compatqual.NonNullType" />
</list>
</value>
</option>
</component>
<component name="ProjectRootManager" version="2" languageLevel="JDK_1_7" project-jdk-name="JDK" project-jdk-type="JavaSDK">
<component name="ProjectRootManager" version="2" languageLevel="JDK_1_8" project-jdk-name="JDK" project-jdk-type="JavaSDK">
<output url="file://$PROJECT_DIR$/build/classes" />
</component>
<component name="ProjectType">

@ -2,7 +2,6 @@
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://F:\Android\yuanMusicPlay\MusicPlayer.iml" filepath="F:\Android\yuanMusicPlay\MusicPlayer.iml" />
<module fileurl="file://$PROJECT_DIR$/app/app.iml" filepath="$PROJECT_DIR$/app/app.iml" />
<module fileurl="file://$PROJECT_DIR$/yuanMusicPlay.iml" filepath="$PROJECT_DIR$/yuanMusicPlay.iml" />
</modules>

@ -16,6 +16,10 @@ android {
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
compileOptions {
sourceCompatibility = '1.8'
targetCompatibility = '1.8'
}
}
allprojects {
repositories {

@ -12,6 +12,7 @@ public class BaseUri {
public static String QQ_URL="https://api.bzqll.com/music/tencent/";
public static String STORAGE_IMG_FILE=MyApplication.getContext().getExternalFilesDir("") + "/yuanmusic/img/";
public static String STORAGE_LRC_FILE=MyApplication.getContext().getExternalFilesDir("") + "/yuanmusic/lrc/";
public static final String BASE_API_URL_LASTFM = "http://ws.audioscrobbler.com/2.0/";
}

@ -1,15 +1,19 @@
package com.example.musicplayer.contract;
import com.example.musicplayer.entiy.Love;
import com.example.musicplayer.entiy.SeachSong;
import com.example.musicplayer.entiy.Song;
import java.util.List;
/**
* Created by on 2018/10/26.
*/
public interface IPlayContract {
interface Model{
void getSingerImg(String singer);//网络请求获得歌手uri
void getSingerImg(String singer,String song,long duration);//网络请求获得歌手uri
void getLrc(String song,long duration);//网络获取歌词
void queryLove(String songId);//查询我喜欢的数据库中有没这首歌
void saveToLove(Song song); //添加到我喜欢的表
void deleteFromLove(String songId); //从我喜欢的表中移除
@ -23,11 +27,16 @@ public interface IPlayContract {
void showLoveAnim(); //喜欢的动画
void saveToLoveSuccess();//保存到我喜欢数据库成功
void sendUpdateCollection(); //发送广播更新收藏列表
void showLrcMessage(String lrc); //显示歌词获取信息
}
interface Presenter{
void getSingerImg(String singer);
void getSingerImg(String singer,String song,long duration);
void getLrc(String song,long duration);
void getSingerImgSuccess(String ImgUrl); //成功获取图片
void getSongLrcSuccess(List<SeachSong.DataBean> dataBeans,long duration); //成功获取歌词
void getSongLrcFail(); //获取歌词失败
void getSingerImgFail(); //请求失败
void showNetWorkError();//网络超时
void queryLove(String songId);//查询我喜欢的数据库中有没这首歌
void saveToLove(Song song); //添加到我喜欢的表
void deleteFromLove(String songId); //从我喜欢的表中移除

@ -0,0 +1,49 @@
package com.example.musicplayer.entiy;
/**
* <pre>
* author :
* time : 2019/03/18
* desc :
* </pre>
*/
public class LrcBean {
private String lrc;
private long start;
private long end;
public LrcBean() {
}
public LrcBean(String text, long start, long end) {
this.lrc = text;
this.start = start;
this.end = end;
}
public String getLrc() {
return lrc;
}
public void setLrc(String lrc) {
this.lrc = lrc;
}
public long getStart() {
return start;
}
public void setStart(long start) {
this.start = start;
}
public long getEnd() {
return end;
}
public void setEnd(long end) {
this.end = end;
}
}

@ -21,4 +21,12 @@ public interface SearchApi {
@GET("search?key=579621905&type=album&limit=30")
Observable<Album> searchAlbum(@Query("s") String seek,@Query("offset")int offset);
/**
*
* @param seek
* @return
*/
@GET("search?key=579621905&type=song&limit=10&offset=0")
Observable<SeachSong> search(@Query("s") String seek);
}

@ -1,11 +1,14 @@
package com.example.musicplayer.https.api;
import com.example.musicplayer.entiy.SeachSong;
import com.example.musicplayer.entiy.SingerImg;
import io.reactivex.Observable;
import retrofit2.http.Field;
import retrofit2.http.FormUrlEncoded;
import retrofit2.http.GET;
import retrofit2.http.POST;
import retrofit2.http.Query;
/**
* Created by on 2018/10/26.
@ -15,4 +18,5 @@ public interface SingerImgApi {
@POST("web?csrf_token=&type=100")
@FormUrlEncoded
Observable<SingerImg> getSingerImg(@Field("s")String singer);
}

@ -5,6 +5,7 @@ import android.util.Log;
import com.example.musicplayer.configure.Constant;
import com.example.musicplayer.contract.IPlayContract;
import com.example.musicplayer.entiy.Love;
import com.example.musicplayer.entiy.SeachSong;
import com.example.musicplayer.entiy.SingerImg;
import com.example.musicplayer.entiy.Song;
import com.example.musicplayer.https.NetWork;
@ -15,13 +16,19 @@ import org.litepal.crud.callback.FindMultiCallback;
import org.litepal.crud.callback.SaveCallback;
import org.litepal.crud.callback.UpdateOrDeleteCallback;
import java.net.UnknownHostException;
import java.util.List;
import io.reactivex.ObservableSource;
import io.reactivex.Observer;
import io.reactivex.Scheduler;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.disposables.Disposable;
import io.reactivex.functions.Consumer;
import io.reactivex.functions.Function;
import io.reactivex.schedulers.Schedulers;
import static com.example.musicplayer.view.AlbumSongFragment.ALBUM_SONG;
/**
@ -38,31 +45,85 @@ public class PlayModel implements IPlayContract.Model {
}
@Override
public void getSingerImg(String singer) {
public void getSingerImg(final String singer, final String song, final long duration) {
NetWork.getSingerImgApi()
.getSingerImg(singer)
.subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread())
.subscribe(new Observer<SingerImg>() {
.doOnNext(new Consumer<SingerImg>() {
@Override
public void accept(SingerImg singerImg) throws Exception {
mPresenter.getSingerImgSuccess(singerImg.getResult().getArtists().get(0).getImg1v1Url());
}
})
.observeOn(Schedulers.io())
.flatMap(new Function<SingerImg, ObservableSource<SeachSong>>() {
@Override
public ObservableSource<SeachSong> apply(SingerImg singerImg) throws Exception {
return NetWork.getSearchApi().search(song);
}
})
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Observer<SeachSong>() {
@Override
public void onSubscribe(Disposable d) {
RxApiManager.get().add(Constant.LOCAL_IMG,d);
RxApiManager.get().add(Constant.LOCAL_IMG, d);
}
@Override
public void onNext(SingerImg value) {
if(value.getCode()==200) {
mPresenter.getSingerImgSuccess(value.getResult().getArtists().get(0).getImg1v1Url());
Log.d(TAG, "onNext: "+value.getResult().getArtists().get(0).getImg1v1Url());
}else{
Log.d(TAG, "onNext: "+value.getCode());
mPresenter.getSingerImgFail();
public void onNext(SeachSong value) {
if (value.getCode() == 200) {
mPresenter.getSongLrcSuccess(value.getData(),duration);
} else {
mPresenter.getSongLrcFail();
}
}
@Override
public void onError(Throwable e) {
Log.d(TAG, "onError: " + e.toString());
if (e instanceof UnknownHostException) {
mPresenter.getSongLrcFail();
} else {
mPresenter.getSongLrcFail();
}
}
@Override
public void onComplete() {
}
});
}
@Override
public void getLrc(String song, long duration) {
NetWork.getSearchApi().search(song)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Observer<SeachSong>() {
@Override
public void onSubscribe(Disposable d) {
RxApiManager.get().add(Constant.LOCAL_IMG, d);
}
@Override
public void onNext(SeachSong value) {
if (value.getCode() == 200) {
mPresenter.getSongLrcSuccess(value.getData(),duration);
} else {
mPresenter.getSongLrcFail();
}
}
@Override
public void onError(Throwable e) {
e.printStackTrace();
mPresenter.getSingerImgFail();
Log.d(TAG, "onError: " + e.toString());
if (e instanceof UnknownHostException) {
mPresenter.getSongLrcFail();
} else {
mPresenter.getSongLrcFail();
}
}
@Override

@ -1,25 +1,37 @@
package com.example.musicplayer.presenter;
import android.support.design.widget.TabLayout;
import android.util.Log;
import com.example.musicplayer.base.BasePresenter;
import com.example.musicplayer.contract.IPlayContract;
import com.example.musicplayer.entiy.SeachSong;
import com.example.musicplayer.entiy.Song;
import com.example.musicplayer.model.PlayModel;
import com.example.musicplayer.util.MediaUtil;
import java.util.List;
/**
* Created by on 2018/10/26.
*/
public class PlayPresenter extends BasePresenter<IPlayContract.View> implements IPlayContract.Presenter {
private static final String TAG = "PlayPresenter";
private PlayModel mModel;
public PlayPresenter(){
mModel=new PlayModel(this);
}
@Override
public void getSingerImg(String singer, String song,long duration) {
mModel.getSingerImg(singer,song,duration);
}
@Override
public void getSingerImg(String singer) {
mModel.getSingerImg(singer);
public void getLrc(String song, long duration) {
mModel.getLrc(song,duration);
}
@Override
@ -29,6 +41,30 @@ public class PlayPresenter extends BasePresenter<IPlayContract.View> implements
}
}
@Override
public void getSongLrcSuccess(List<SeachSong.DataBean> dataBeans,long duration) {
if(isAttachView()){
Log.d(TAG, "getSongLrcSuccess: duration="+MediaUtil.formatLongToThree(duration));
boolean isLrc =false;
for(SeachSong.DataBean dataBean : dataBeans){
if(dataBean.getTime() == MediaUtil.formatLongToThree(duration)){
isLrc = true;
getMvpView().showLrcMessage(dataBean.getLrc());
break;
}
}
Log.d(TAG, "getSongLrcSuccess: "+isLrc);
if(!isLrc) getMvpView().showLrcMessage(dataBeans.get(0).getLrc());
}
}
@Override
public void getSongLrcFail() {
if(isAttachView()){
getMvpView().showLrcMessage(null);
}
}
@Override
public void getSingerImgFail() {
if(isAttachView()){
@ -36,6 +72,11 @@ public class PlayPresenter extends BasePresenter<IPlayContract.View> implements
}
}
@Override
public void showNetWorkError() {
}
@Override
public void queryLove(String songId) {
mModel.queryLove(songId);

@ -40,7 +40,6 @@ public class FileHelper {
try {
File file = new File(MyApplication.getContext().getExternalFilesDir("yuanmusic").getAbsolutePath());
if (!file.exists()) {
Log.d("Login", "------------------" + MyApplication.getContext().getExternalFilesDir(""));
file.mkdirs();
}
//写对象流的对象

@ -0,0 +1,90 @@
package com.example.musicplayer.util;
import com.example.musicplayer.entiy.LrcBean;
import java.util.ArrayList;
import java.util.List;
/**
* <pre>
* author :
* time : 2019/03/18
* desc :
* </pre>
*/
public class LrcUtil {
/**
*
*
* @param lrcStr
* @return
*/
public static List<LrcBean> parseStr2List(String lrcStr) {
List<LrcBean> list = new ArrayList<>();
String lrcText = lrcStr.replaceAll("&#58;", ":")
.replaceAll("&apos;", "'")
.replaceAll("&#10;", "\n")
.replaceAll("&#46;", ".")
.replaceAll("&#32;", " ")
.replaceAll("&#45;", "-")
.replaceAll("&#13;", "\r")
.replaceAll("&#39;", "'");
String[] split = lrcText.split("\n");
for (int i = 4; i < split.length; i++) {
String lrc = split[i];
if (lrc.contains(".")) {
String min = lrc.substring(lrc.indexOf("[") + 1, lrc.indexOf("[") + 3);
String seconds = lrc.substring(lrc.indexOf(":") + 1, lrc.indexOf(":") + 3);
String mills = lrc.substring(lrc.indexOf(".") + 1, lrc.indexOf(".") + 3);
long startTime = Long.valueOf(min) * 60 * 1000 + Long.valueOf(seconds) * 1000 + Long.valueOf(mills) * 10;
String text = lrc.substring(lrc.indexOf("]") + 1);
if (text.equals("") || text == null) continue;
if (i == 5) {
int first = text.indexOf("(");
int second = text.indexOf("(", first + 1);
String textFront = null;
String textBehind = null;
boolean isTwo = true;
boolean isOne = true;
try {
textFront = text.substring(0, first);
}catch (StringIndexOutOfBoundsException e){
isOne = false;
}
try {
textBehind = text.substring(first + 1, second);
} catch (StringIndexOutOfBoundsException e) {
isTwo = false;
}
LrcBean lrcBean1 = new LrcBean();
lrcBean1.setStart(startTime);
if(isOne) {
lrcBean1.setLrc(textFront);
} else {
lrcBean1.setLrc(text);
}
list.add(lrcBean1);
if (isTwo) {
LrcBean lrcBean2 = new LrcBean();
lrcBean2.setStart(startTime);
lrcBean2.setLrc(textBehind);
list.add(lrcBean2);
}
} else {
LrcBean lrcBean = new LrcBean();
lrcBean.setStart(startTime);
lrcBean.setLrc(text);
list.add(lrcBean);
}
if (list.size() > 1) {
list.get(list.size() - 2).setEnd(startTime);
}
if (i == split.length - 1) {
list.get(list.size() - 1).setEnd(startTime + 100000);
}
}
}
return list;
}
}

@ -49,6 +49,10 @@ public class MediaUtil {
return singer.trim();
}
public static long formatLongToThree(long duration){
return (duration/1000);
}
}

@ -91,7 +91,7 @@ public class MainFragment extends Fragment {
mAlbumCollectionList = new ArrayList<>();
AlbumCollection albumCollection = new AlbumCollection();
albumCollection.setAlbumName("我喜欢");
albumCollection.setSingerName("袁健策");
albumCollection.setSingerName("残渊");
mLoveAlbumList.add(albumCollection);
mAlbumCollectionList.add(mLoveAlbumList);
mAlbumCollectionList.add(orderCollection(LitePal.findAll(AlbumCollection.class)));

@ -55,9 +55,21 @@ import com.example.musicplayer.util.MediaUtil;
import com.example.musicplayer.util.RxApiManager;
import com.example.musicplayer.widget.BackgroundAnimationRelativeLayout;
import com.example.musicplayer.widget.DiscView;
import org.litepal.LitePal;
import com.example.musicplayer.widget.LrcView;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.List;
/**
@ -92,6 +104,8 @@ public class PlayActivity extends BaseActivity implements IPlayContract.View {
private TextView mCurrentTimeTv;
private TextView mDurationTimeTv;
private String mLrc = null;
private Button mLoveBtn;
private boolean isLove;//是否已经在我喜欢的列表中
@ -102,6 +116,7 @@ public class PlayActivity extends BaseActivity implements IPlayContract.View {
private Button mGetImgAndLrcBtn;//获取封面和歌词
private BackgroundAnimationRelativeLayout mRootLayout;
private List<LocalSong> mLocalSong;//用来判断是否有本地照片
private LrcView mLrcView; //歌词自定义View
//服务
private Thread mSeekBarThread;
@ -124,14 +139,14 @@ public class PlayActivity extends BaseActivity implements IPlayContract.View {
}
} else {
setLocalImg(mSong.getSinger());
mSeekBar.setSecondaryProgress((int)mSong.getDuration());
mSeekBar.setSecondaryProgress((int) mSong.getDuration());
}
mDurationTimeTv.setText(MediaUtil.formatTime(mSong.getDuration()));
//缓存进度条
mPlayStatusBinder.getMediaPlayer().setOnBufferingUpdateListener(new MediaPlayer.OnBufferingUpdateListener() {
@Override
public void onBufferingUpdate(MediaPlayer mp, int percent) {
mSeekBar.setSecondaryProgress(percent*mSeekBar.getProgress());
mSeekBar.setSecondaryProgress(percent * mSeekBar.getProgress());
}
});
}
@ -192,6 +207,7 @@ public class PlayActivity extends BaseActivity implements IPlayContract.View {
mDiscImg = findViewById(R.id.iv_disc_background);
mLoveBtn = findViewById(R.id.btn_love);
mOrderBtn = findViewById(R.id.btn_order);
mLrcView = findViewById(R.id.lrcView);
//界面填充
mSong = FileHelper.getSong();
@ -288,7 +304,6 @@ public class PlayActivity extends BaseActivity implements IPlayContract.View {
@Override
public void onStopTrackingTouch(SeekBar seekBar) {
if (mPlayStatusBinder.isPlaying()) {
Log.d(TAG, "onStopTrackingTouch: isPlay");
mMediaPlayer = mPlayStatusBinder.getMediaPlayer();
mMediaPlayer.seekTo(seekBar.getProgress());
startUpdateSeekBarProgress();
@ -304,7 +319,7 @@ public class PlayActivity extends BaseActivity implements IPlayContract.View {
mOrderBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
CommonUtil.showToast(PlayActivity.this,"抱歉,目前只支持顺序播放,其他功能还在开发中");
CommonUtil.showToast(PlayActivity.this, "抱歉,目前只支持顺序播放,其他功能还在开发中");
}
});
@ -332,7 +347,6 @@ public class PlayActivity extends BaseActivity implements IPlayContract.View {
mPlayBtn.setSelected(true);
startUpdateSeekBarProgress();
} else {
Log.d(TAG, "onClick: --------play");
if (isOnline) {
mPlayStatusBinder.playOnline();
} else {
@ -370,16 +384,35 @@ public class PlayActivity extends BaseActivity implements IPlayContract.View {
@Override
public void onClick(View v) {
showLoveAnim();
if(isLove){
if (isLove) {
mLoveBtn.setSelected(false);
mPresenter.deleteFromLove(FileHelper.getSong().getSongId());
}else {
} else {
mLoveBtn.setSelected(true);
mPresenter.saveToLove(FileHelper.getSong());
}
isLove = !isLove;
}
});
//唱碟点击效果
mDisc.setOnClickListener(v -> {
if (!isOnline) {
if (getLrcFromLocal().equals("")) {
mPresenter.getLrc(getSongName(), mSong.getDuration());
}
showLrc(getLrcFromLocal());
} else {
mPresenter.getLrc(getSongName(), mSong.getDuration());
}
}
);
//歌词点击效果
mLrcView.setOnClickListener(v -> {
mLrcView.setVisibility(View.GONE);
mDisc.setVisibility(View.VISIBLE);
});
}
@Override
@ -394,15 +427,19 @@ public class PlayActivity extends BaseActivity implements IPlayContract.View {
}
private String getSongName() {
Song song = FileHelper.getSong();
return song.getSongName().trim();
}
@Override
public void getSingerAndLrc() {
mGetImgAndLrcBtn.setText("正在获取...");
mPresenter.getSingerImg(getSingerName());
mPresenter.getSingerImg(getSingerName(), getSongName(), mSong.getDuration());
}
@Override
public void setSingerImg(String ImgUrl) {
Log.d(TAG, "setSingerImg: success");
SimpleTarget target = new SimpleTarget<Drawable>(Target.SIZE_ORIGINAL, Target.SIZE_ORIGINAL) {
@Override
public void onResourceReady(@Nullable Drawable resource, Transition<? super Drawable> transition) {
@ -411,11 +448,10 @@ public class PlayActivity extends BaseActivity implements IPlayContract.View {
if (!isOnline) {
//保存图片到本地
FileHelper.saveImgToNative(PlayActivity.this, mImgBmp, getSingerName());
CommonUtil.showToast(PlayActivity.this, "获取封面歌词成功");
//将封面地址放到数据库中
LocalSong localSong =new LocalSong();
LocalSong localSong = new LocalSong();
localSong.setPic(BaseUri.STORAGE_IMG_FILE + FileHelper.getSong().getSinger() + ".jpg");
localSong.updateAll("songId=?",FileHelper.getSong().getSongId());
localSong.updateAll("songId=?", FileHelper.getSong().getSongId());
}
try2UpdateMusicPicBackground(mImgBmp);
@ -438,13 +474,13 @@ public class PlayActivity extends BaseActivity implements IPlayContract.View {
@Override
public void showLove(final boolean love) {
isLove =love;
isLove = love;
runOnUiThread(new Runnable() {
@Override
public void run() {
if(love){
if (love) {
mLoveBtn.setSelected(true);
}else{
} else {
mLoveBtn.setSelected(false);
}
}
@ -461,7 +497,7 @@ public class PlayActivity extends BaseActivity implements IPlayContract.View {
@Override
public void saveToLoveSuccess() {
CommonUtil.showToast(PlayActivity.this,"添加成功");
CommonUtil.showToast(PlayActivity.this, "添加成功");
}
@Override
@ -469,11 +505,21 @@ public class PlayActivity extends BaseActivity implements IPlayContract.View {
sendBroadcast(new Intent(BroadcastName.LOVE_SONG_CANCEL));
}
@Override
public void showLrcMessage(String lrc) {
if (lrc == null) {
CommonUtil.showToast(PlayActivity.this, "抱歉,获取不到该歌曲的歌词信息");
mLrc = null;
} else {
mLrc = lrc;
saveLrcToLocal();
}
}
//设置唱碟中歌手头像
private void setDiscImg(Bitmap bitmap) {
mDiscImg.setImageDrawable(mDisc.getDiscDrawable(bitmap));
int marginTop = (int) (DisplayUtil.SCALE_DISC_MARGIN_TOP * CommonUtil.getScreenHeight(PlayActivity.this));
RelativeLayout.LayoutParams layoutParams = (RelativeLayout.LayoutParams) mDiscImg
.getLayoutParams();
@ -486,6 +532,8 @@ public class PlayActivity extends BaseActivity implements IPlayContract.View {
@Override
public void onReceive(Context context, Intent intent) {
mDisc.setVisibility(View.VISIBLE);
mLrcView.setVisibility(View.GONE);
Song mSong = FileHelper.getSong();
mSongTv.setText(mSong.getSongName());
mSingerTv.setText(mSong.getSinger());
@ -497,8 +545,8 @@ public class PlayActivity extends BaseActivity implements IPlayContract.View {
mPlayStatusBinder.getMediaPlayer().setOnBufferingUpdateListener(new MediaPlayer.OnBufferingUpdateListener() {
@Override
public void onBufferingUpdate(MediaPlayer mp, int percent) {
Log.d(TAG, "onBufferingUpdate: "+percent);
mSeekBar.setSecondaryProgress(percent*mSeekBar.getProgress());
Log.d(TAG, "onBufferingUpdate: " + percent);
mSeekBar.setSecondaryProgress(percent * mSeekBar.getProgress());
}
});
mPresenter.queryLove(mSong.getSongId()); //查找歌曲是否为我喜欢的歌曲
@ -521,7 +569,6 @@ public class PlayActivity extends BaseActivity implements IPlayContract.View {
}
private void setLocalImg(String singer) {
String imgUrl = BaseUri.STORAGE_IMG_FILE + MediaUtil.formatSinger(singer) + ".jpg";
SimpleTarget target = new SimpleTarget<Drawable>(Target.SIZE_ORIGINAL, Target.SIZE_ORIGINAL) {
@Override
@ -555,6 +602,104 @@ public class PlayActivity extends BaseActivity implements IPlayContract.View {
}
private void saveLrcToLocal() {
new Thread(new Runnable() {
@Override
public void run() {
HttpURLConnection urlConnection = null;
BufferedReader reader = null;
BufferedWriter writer = null;
try {
URL url = new URL(mLrc);
urlConnection = (HttpURLConnection) url.openConnection();
urlConnection.setRequestMethod("GET");
InputStream inputStream = urlConnection.getInputStream();
reader = new BufferedReader(new InputStreamReader(inputStream));
StringBuilder lrcBuilder = new StringBuilder();
String lrc;
/**
*
*/
if (!isOnline) {
File file = new File(BaseUri.STORAGE_LRC_FILE);
if (!file.exists()) {
file.mkdirs();
}
File lrcFile = new File(file, getSongName() + ".lrc");
FileOutputStream outputStream = new FileOutputStream(lrcFile);
OutputStreamWriter outputStreamWriter = new OutputStreamWriter(outputStream, "gbk");
writer = new BufferedWriter(outputStreamWriter);
}
while ((lrc = reader.readLine()) != null) {
if (isOnline) {
lrcBuilder.append(lrc);
lrcBuilder.append("\n");
} else {
//写入
writer.write(lrc);
writer.newLine();
}
}
if (isOnline) showLrc(lrcBuilder.toString());
} catch (Exception e) {
e.printStackTrace();
} finally {
if (urlConnection != null) urlConnection.disconnect();
try {
if (reader != null) reader.close();
if (writer != null) writer.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}).start();
}
/**
*
*/
private String getLrcFromLocal() {
try {
InputStream inputStream = new FileInputStream(new File(BaseUri.STORAGE_LRC_FILE + getSongName() + ".lrc"));
ByteArrayOutputStream os = new ByteArrayOutputStream();
byte[] buffer = new byte[1024];
int len = -1;
while ((len = inputStream.read(buffer)) != -1) {
os.write(buffer, 0, len);
}
Log.d(TAG, "getLrcFromLocal: "+os.toString("gbk"));
return os.toString("gbk"); //文件编码是gbk
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return "";
}
/**
*
*
* @param lrc
*/
private void showLrc(final String lrc) {
runOnUiThread(new Runnable() {
@Override
public void run() {
mDisc.setVisibility(View.GONE);
mLrcView.setVisibility(View.VISIBLE);
mLrcView.setLrc(lrc);
mLrcView.setHighLineColor(getResources().getColor(R.color.musicStyle));
mLrcView.setPlayer(mPlayStatusBinder.getMediaPlayer());
mLrcView.init();
}
});
}
@Override
public void onDestroy() {
super.onDestroy();

@ -57,7 +57,7 @@ public class WelcomeActivity extends AppCompatActivity {
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
mHandler.sendEmptyMessageDelayed(0, 2000);
} else {
Toast.makeText(this, "软件工程3班袁健策 3117004905\n拒绝该权限无法使用该程序", Toast.LENGTH_SHORT).show();
Toast.makeText(this, "拒绝该权限无法使用该程序", Toast.LENGTH_SHORT).show();
finish();
}
break;

@ -0,0 +1,194 @@
package com.example.musicplayer.widget;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.media.MediaPlayer;
import android.util.AttributeSet;
import android.view.View;
import com.example.musicplayer.R;
import com.example.musicplayer.entiy.LrcBean;
import com.example.musicplayer.util.LrcUtil;
import java.util.List;
/**
* <pre>
* author :
* time : 2019/03/18
* desc :
* </pre>
*/
public class LrcView extends View {
private List<LrcBean> list;
private Paint gPaint;
private Paint hPaint;
private int width = 0, height = 0;
private int currentPosition = 0;
private MediaPlayer player;
private int lastPosition = 0;
private int highLineColor;
private int lrcTextSize;
private int lrcColor;
private int mode = 0;
public final static int KARAOKE = 1;
public void setHighLineColor(int highLineColor) {
this.highLineColor = highLineColor;
}
public void setLrcColor(int lrcColor) {
this.lrcColor = lrcColor;
}
public void setMode(int mode) {
this.mode = mode;
}
public void setPlayer(MediaPlayer player) {
this.player = player;
}
/**
*
*
* @param lrc
*/
public void setLrc(String lrc) {
list = LrcUtil.parseStr2List(lrc);
}
public LrcView(Context context) {
this(context, null);
}
public LrcView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public LrcView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.LrcView);
highLineColor = ta.getColor(R.styleable.LrcView_hignLineColor, getResources().getColor(R.color.green));
lrcColor = ta.getColor(R.styleable.LrcView_lrcColor, getResources().getColor(android.R.color.darker_gray));
float densityText = getResources().getDisplayMetrics().scaledDensity;
lrcTextSize = ta.getDimensionPixelSize(R.styleable.LrcView_lrcTextSize,(int)(16*densityText));
mode = ta.getInt(R.styleable.LrcView_lrcMode,mode);
ta.recycle();
gPaint = new Paint();
gPaint.setAntiAlias(true);
gPaint.setColor(lrcColor);
gPaint.setTextSize(lrcTextSize);
gPaint.setTextAlign(Paint.Align.CENTER);
hPaint = new Paint();
hPaint.setAntiAlias(true);
hPaint.setColor(highLineColor);
hPaint.setTextSize(lrcTextSize);
hPaint.setTextAlign(Paint.Align.CENTER);
}
@Override
protected void onDraw(Canvas canvas) {
if (width == 0 || height == 0) {
width = getMeasuredWidth();
height = getMeasuredHeight();
}
if (list == null || list.size() == 0) {
canvas.drawText("暂无歌词", width / 2, height / 2, gPaint);
return;
}
getCurrentPosition();
int currentMillis = player.getCurrentPosition();
drawLrc2(canvas, currentMillis);
long start = list.get(currentPosition).getStart();
float v = (currentMillis - start) > 500 ? currentPosition * 120 : lastPosition * 120 + (currentPosition - lastPosition) * 120 * ((currentMillis - start) / 500f);
setScrollY((int) v);
if (getScrollY() == currentPosition * 120) {
lastPosition = currentPosition;
}
postInvalidateDelayed(100);
}
private void drawLrc2(Canvas canvas, int currentMillis) {
if (mode == 0) {
for (int i = 0; i < list.size(); i++) {
if (i == currentPosition) {
canvas.drawText(list.get(i).getLrc(), width / 2, height / 2 + 120 * i, hPaint);
} else {
canvas.drawText(list.get(i).getLrc(), width / 2, height / 2 + 120 * i, gPaint);
}
}
}else{
for (int i = 0; i < list.size(); i++) {
canvas.drawText(list.get(i).getLrc(), width / 2, height / 2 + 80 * i, gPaint);
}
String highLineLrc = list.get(currentPosition).getLrc();
int highLineWidth = (int) gPaint.measureText(highLineLrc);
int leftOffset = (width - highLineWidth) / 2;
LrcBean lrcBean = list.get(currentPosition);
long start = lrcBean.getStart();
long end = lrcBean.getEnd();
int i = (int) ((currentMillis - start) * 1.0f / (end - start) * highLineWidth);
if (i > 0) {
Bitmap textBitmap = Bitmap.createBitmap(i, 80, Bitmap.Config.ARGB_8888);
Canvas textCanvas = new Canvas(textBitmap);
textCanvas.drawText(highLineLrc, highLineWidth / 2, 80, hPaint);
canvas.drawBitmap(textBitmap, leftOffset, height / 2 + 80 * (currentPosition - 1), null);
}
}
}
public void init() {
currentPosition = 0;
lastPosition = 0;
setScrollY(0);
invalidate();
}
private void drawLrc1(Canvas canvas) {
String text = list.get(currentPosition).getLrc();
canvas.drawText(text, width / 2, height / 2, hPaint);
for (int i = 1; i < 10; i++) {
int index = currentPosition - i;
if (index > -1) {
canvas.drawText(list.get(index).getLrc(), width / 2, height / 2 - 100 * i, gPaint);
}
}
for (int i = 1; i < 10; i++) {
int index = currentPosition + i;
if (index < list.size()) {
canvas.drawText(list.get(index).getLrc(), width / 2, height / 2 + 100 * i, gPaint);
}
}
}
private void getCurrentPosition() {
try {
int currentMillis = player.getCurrentPosition();
if (currentMillis < list.get(0).getStart()) {
currentPosition = 0;
return;
}
if (currentMillis > list.get(list.size() - 1).getStart()) {
currentPosition = list.size() - 1;
return;
}
for (int i = 0; i < list.size(); i++) {
if (currentMillis >= list.get(i).getStart() && currentMillis < list.get(i).getEnd()) {
currentPosition = i;
return;
}
}
} catch (Exception e) {
postInvalidateDelayed(100);
}
}
}

@ -1,5 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<com.example.musicplayer.widget.BackgroundAnimationRelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/relative_root"
android:layout_width="match_parent"
android:layout_height="match_parent"
@ -59,12 +60,23 @@
android:layout_below="@+id/relative_song"
android:background="#33ffffff" />
<com.example.musicplayer.widget.LrcView
android:id="@+id/lrcView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginTop="@dimen/dp_40"
android:layout_marginBottom="@dimen/dp_40"
android:layout_below="@+id/relative_song"
android:layout_above="@+id/relative_music_time"
app:lrcTextSize="18sp"
app:hignLineColor="@color/musicStyle"
android:visibility="gone"/>
<include
android:id="@+id/disc_view"
layout="@layout/layout_discview"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_above="@+id/rlMusicTime"
android:layout_below="@+id/relative_song" />
<Button

@ -4,6 +4,7 @@
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@drawable/dialog_bg">
<TextView
android:id="@+id/tv_dialog_delete_title"
android:layout_width="match_parent"

@ -20,8 +20,6 @@
android:layout_height="match_parent"
android:layout_marginBottom="65dp"
android:visibility="gone">
</com.github.jdsjlzx.recyclerview.LRecyclerView>
<com.wang.avi.AVLoadingIndicatorView

@ -6,4 +6,15 @@
<attr name="civ_border_overlay" format="boolean" />
<attr name="civ_fill_color" format="color" />
</declare-styleable>
</resources>
<declare-styleable name="LrcView">
<attr name="lrcMode" format="enum">
<enum name="KARAOKE" value="1"/>
</attr>
<attr name="hignLineColor" format="color|reference"/>
<attr name="lrcColor" format="color|reference"/>
<attr name="lrcTextSize" format="dimension"/>
</declare-styleable>
</resources>

@ -1,7 +1,7 @@
<resources>
<string name="app_name">心渊音乐</string>
<string name="name">袁健策(软件工程3班)</string>
<string name="student_id">3117004905</string>
<string name="name">残渊</string>
<string name="student_id">jay0712</string>
<string name="seek">搜索</string>
<string name="local_music">本地音乐</string>
<string name="collection">我的收藏</string>

@ -3,6 +3,7 @@
buildscript {
repositories {
mavenCentral()
google()
jcenter()
}

Loading…
Cancel
Save