├── .gitignore ├── .idea ├── compiler.xml ├── copyright │ └── profiles_settings.xml ├── encodings.xml ├── gradle.xml ├── inspectionProfiles │ ├── Project_Default.xml │ └── profiles_settings.xml ├── misc.xml ├── modules.xml ├── runConfigurations.xml └── vcs.xml ├── README.md ├── app ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── linkedlistview │ │ └── sample │ │ └── github │ │ └── linkedlistview │ │ └── ExampleInstrumentedTest.java │ ├── main │ ├── AndroidManifest.xml │ ├── java │ │ └── linkedlistview │ │ │ └── sample │ │ │ └── github │ │ │ └── linkedlistview │ │ │ ├── controller │ │ │ ├── adapter │ │ │ │ ├── MusicHeaderAdapter.java │ │ │ │ ├── MusicListAdapter.java │ │ │ │ └── PlaylistPagerAdapter.java │ │ │ └── animation │ │ │ │ ├── ActivityAnimator.java │ │ │ │ └── MusicHeaderAnimator.java │ │ │ ├── model │ │ │ ├── AnimBounceTask.java │ │ │ ├── AnimPaddingTask.java │ │ │ ├── MusicHeaderItem.java │ │ │ └── MusicListItem.java │ │ │ ├── stub │ │ │ └── StubItems.java │ │ │ └── view │ │ │ ├── ActivityMainPlay.java │ │ │ ├── ActivitySplash.java │ │ │ ├── FragmentPlaylist.java │ │ │ ├── base │ │ │ └── BaseActivity.java │ │ │ └── helper │ │ │ └── FirstFocusedStartListener.java │ └── res │ │ ├── drawable │ │ ├── music_album_photo_1.jpg │ │ ├── music_album_photo_10.jpg │ │ ├── music_album_photo_11.jpg │ │ ├── music_album_photo_12.jpg │ │ ├── music_album_photo_13.jpg │ │ ├── music_album_photo_14.jpg │ │ ├── music_album_photo_15.jpg │ │ ├── music_album_photo_16.jpg │ │ ├── music_album_photo_17.jpg │ │ ├── music_album_photo_18.jpg │ │ ├── music_album_photo_19.jpg │ │ ├── music_album_photo_2.jpg │ │ ├── music_album_photo_20.jpg │ │ ├── music_album_photo_21.jpg │ │ ├── music_album_photo_22.jpg │ │ ├── music_album_photo_3.jpg │ │ ├── music_album_photo_4.jpg │ │ ├── music_album_photo_5.jpg │ │ ├── music_album_photo_6.jpg │ │ ├── music_album_photo_7.jpg │ │ ├── music_album_photo_8.jpg │ │ └── music_album_photo_9.jpg │ │ ├── layout │ │ ├── activity_main_content.xml │ │ ├── activity_main_header.xml │ │ ├── activity_splash.xml │ │ ├── adapter_music_header_item.xml │ │ ├── adapter_music_list_item.xml │ │ └── fragment_playlist.xml │ │ ├── mipmap-hdpi │ │ ├── ic_launcher.png │ │ ├── ic_pause_circle_black_24dp.png │ │ ├── ic_play_circle_filled_black_24dp.png │ │ ├── ic_skip_next_circle_black_24dp.png │ │ ├── ic_skip_previous_circle_black_24dp.png │ │ └── ic_star_black_24dp.png │ │ ├── mipmap-mdpi │ │ ├── ic_launcher.png │ │ ├── ic_pause_circle_black_24dp.png │ │ ├── ic_play_circle_filled_black_24dp.png │ │ ├── ic_skip_next_circle_black_24dp.png │ │ ├── ic_skip_previous_circle_black_24dp.png │ │ └── ic_star_black_24dp.png │ │ ├── mipmap-xhdpi │ │ ├── ic_launcher.png │ │ ├── ic_pause_circle_black_24dp.png │ │ ├── ic_play_circle_filled_black_24dp.png │ │ ├── ic_skip_next_circle_black_24dp.png │ │ ├── ic_skip_previous_circle_black_24dp.png │ │ └── ic_star_black_24dp.png │ │ ├── mipmap-xxhdpi │ │ ├── ic_launcher.png │ │ ├── ic_pause_circle_black_24dp.png │ │ ├── ic_play_circle_filled_black_24dp.png │ │ ├── ic_skip_next_circle_black_24dp.png │ │ ├── ic_skip_previous_circle_black_24dp.png │ │ └── ic_star_black_24dp.png │ │ ├── mipmap-xxxhdpi │ │ ├── ic_launcher.png │ │ ├── ic_pause_circle_black_24dp.png │ │ ├── ic_play_circle_filled_black_24dp.png │ │ ├── ic_skip_next_circle_black_24dp.png │ │ ├── ic_skip_previous_circle_black_24dp.png │ │ └── ic_star_black_24dp.png │ │ ├── raw │ │ └── sample_song_1.mp3 │ │ ├── values-v21 │ │ └── styles.xml │ │ ├── values-w820dp │ │ └── dimens.xml │ │ └── values │ │ ├── colors.xml │ │ ├── dimens.xml │ │ ├── strings.xml │ │ └── styles.xml │ └── test │ └── java │ └── linkedlistview │ └── sample │ └── github │ └── linkedlistview │ └── ExampleUnitTest.java ├── autodimension.gradle ├── build.gradle ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── screens ├── giphy1.gif ├── giphy2.gif └── giphy3.gif └── settings.gradle /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | /.idea/workspace.xml 5 | /.idea/libraries 6 | .DS_Store 7 | /build 8 | /captures 9 | .externalNativeBuild 10 | -------------------------------------------------------------------------------- /.idea/compiler.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /.idea/copyright/profiles_settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /.idea/encodings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /.idea/gradle.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 17 | 18 | -------------------------------------------------------------------------------- /.idea/inspectionProfiles/Project_Default.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 10 | -------------------------------------------------------------------------------- /.idea/inspectionProfiles/profiles_settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 7 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 19 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 46 | 47 | 48 | 49 | 50 | 1.8 51 | 52 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 68 | 69 | 70 | 71 | 72 | 73 | -------------------------------------------------------------------------------- /.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /.idea/runConfigurations.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 11 | 12 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Sample LinkedListView 2 | 3 | - 4 | Just more complicated Sample for using [LinkedListView library](https://github.com/GensaGames/LinkedListView) for Android. This Project contains a lot of other things and in this scope - complex List Items with different tranlsation during scrolling. See code for more details. 5 | 6 | We will update the Project for other interesting samples based on LinkedListView. Also this work optimized for Nexus 4 Resolution (API 23 768-1280), and maybe later will have other screens support. 7 | 8 | 9 | -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | android { 4 | compileSdkVersion 25 5 | buildToolsVersion "24.0.3" 6 | defaultConfig { 7 | applicationId "linkedlistview.sample.github.sample_linkedlistview" 8 | minSdkVersion 17 9 | targetSdkVersion 25 10 | versionCode 1 11 | versionName "1.0" 12 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" 13 | } 14 | buildTypes { 15 | release { 16 | minifyEnabled false 17 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 18 | } 19 | } 20 | } 21 | 22 | dependencies { 23 | compile fileTree(include: ['*.jar'], dir: 'libs') 24 | androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', { 25 | exclude group: 'com.android.support', module: 'support-annotations' 26 | }) 27 | compile 'com.android.support:appcompat-v7:25.0.0' 28 | compile 'com.github.gensagames:linkedlistview:0.4.7' 29 | compile 'com.android.support:design:25.0.0' 30 | testCompile 'junit:junit:4.12' 31 | compile 'com.jakewharton:butterknife:8.4.0' 32 | annotationProcessor 'com.jakewharton:butterknife-compiler:8.4.0' 33 | compile 'com.thedeanda:lorem:2.1' 34 | compile 'com.squareup.picasso:picasso:2.5.2' 35 | compile 'com.android.support:cardview-v7:25.0.0' 36 | compile 'com.android.support:recyclerview-v7:25.0.0' 37 | compile 'io.gresse.hugo.vumeterlibrary:vumeterlibrary:1.0.15' 38 | compile 'com.cleveroad:audiovisualization:1.0.0' 39 | } 40 | -------------------------------------------------------------------------------- /app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in C:\Android-SDK/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | # If your project uses WebView with JS, uncomment the following 13 | # and specify the fully qualified class name to the JavaScript interface 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 16 | # public *; 17 | #} 18 | -------------------------------------------------------------------------------- /app/src/androidTest/java/linkedlistview/sample/github/linkedlistview/ExampleInstrumentedTest.java: -------------------------------------------------------------------------------- 1 | package linkedlistview.sample.github.linkedlistview; 2 | 3 | import android.content.Context; 4 | import android.support.test.InstrumentationRegistry; 5 | import android.support.test.runner.AndroidJUnit4; 6 | 7 | import org.junit.Test; 8 | import org.junit.runner.RunWith; 9 | 10 | import static org.junit.Assert.*; 11 | 12 | /** 13 | * Instrumentation test, which will execute on an Android device. 14 | * 15 | * @see Testing documentation 16 | */ 17 | @RunWith(AndroidJUnit4.class) 18 | public class ExampleInstrumentedTest { 19 | @Test 20 | public void useAppContext() throws Exception { 21 | // Context of the app under test. 22 | Context appContext = InstrumentationRegistry.getTargetContext(); 23 | 24 | assertEquals("linkedlistview.sample.github.sample_linkedlistview", appContext.getPackageName()); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 22 | 26 | 27 | 28 | 29 | 30 | 31 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /app/src/main/java/linkedlistview/sample/github/linkedlistview/controller/adapter/MusicHeaderAdapter.java: -------------------------------------------------------------------------------- 1 | package linkedlistview.sample.github.linkedlistview.controller.adapter; 2 | 3 | import android.content.Context; 4 | import android.support.v4.content.ContextCompat; 5 | import android.support.v7.widget.CardView; 6 | import android.view.LayoutInflater; 7 | import android.view.View; 8 | import android.view.ViewGroup; 9 | import android.widget.ImageView; 10 | 11 | import com.gensagames.linkedlistview.LinkedListView; 12 | import com.squareup.picasso.Picasso; 13 | 14 | import java.util.ArrayList; 15 | import java.util.LinkedList; 16 | import java.util.List; 17 | 18 | import linkedlistview.sample.github.linkedlistview.R; 19 | import linkedlistview.sample.github.linkedlistview.model.MusicHeaderItem; 20 | 21 | /** 22 | * Created by GensaGames 23 | * GensaGames 24 | */ 25 | 26 | public class MusicHeaderAdapter extends LinkedListView.Adapter { 27 | 28 | private Context mContext; 29 | private List mItemsList; 30 | private List mViewsLinkedList; 31 | 32 | public MusicHeaderAdapter(Context mContext) { 33 | this.mContext = mContext; 34 | mItemsList = new ArrayList<>(); 35 | mViewsLinkedList = new LinkedList<>(); 36 | } 37 | 38 | public void addItem(MusicHeaderItem musicHeaderItem) { 39 | mItemsList.add(musicHeaderItem); 40 | notifyDataSetChanged(); 41 | } 42 | 43 | public void addItemList(List itemList) { 44 | mItemsList.addAll(itemList); 45 | notifyDataSetChanged(); 46 | } 47 | 48 | @Override 49 | public void bindView(LinkedListView.ViewHolder v, int position) { 50 | MusicViewHolder viewHolder = (MusicViewHolder) v; 51 | viewHolder.cardView.setCardBackgroundColor(ContextCompat 52 | .getColor(mContext, android.R.color.white)); 53 | 54 | Picasso.with(mContext).load(mItemsList.get(position).getImageResourceId()) 55 | .error(android.R.drawable.stat_notify_error) 56 | .resize(100, 100) 57 | .into(viewHolder.imageView); 58 | } 59 | 60 | @Override 61 | public int getObjectCount() { 62 | return mItemsList.size(); 63 | } 64 | 65 | @Override 66 | public LinkedListView.ViewHolder getViewHolder(int position, ViewGroup parentView) { 67 | if (position >= mViewsLinkedList.size() || mViewsLinkedList.get(position) == null) { 68 | LayoutInflater inflater = LayoutInflater.from(mContext); 69 | mViewsLinkedList.add(new MusicViewHolder(inflater 70 | .inflate(R.layout.adapter_music_header_item, parentView, false))); 71 | } 72 | return mViewsLinkedList.get(position); 73 | } 74 | 75 | 76 | private static class MusicViewHolder extends LinkedListView.ViewHolder { 77 | 78 | private ImageView imageView; 79 | private CardView cardView; 80 | 81 | MusicViewHolder(View mainView) { 82 | super(mainView); 83 | cardView = (CardView) mainView.findViewById(R.id.adapter_cardview); 84 | imageView = (ImageView) mainView.findViewById(R.id.adapter_item_photo); 85 | } 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /app/src/main/java/linkedlistview/sample/github/linkedlistview/controller/adapter/MusicListAdapter.java: -------------------------------------------------------------------------------- 1 | package linkedlistview.sample.github.linkedlistview.controller.adapter; 2 | 3 | import android.content.Context; 4 | import android.support.v4.content.ContextCompat; 5 | import android.support.v7.widget.RecyclerView; 6 | import android.view.LayoutInflater; 7 | import android.view.View; 8 | import android.view.ViewGroup; 9 | import android.widget.ImageView; 10 | import android.widget.TextView; 11 | 12 | import java.util.LinkedList; 13 | import java.util.List; 14 | 15 | import linkedlistview.sample.github.linkedlistview.R; 16 | import linkedlistview.sample.github.linkedlistview.model.MusicListItem; 17 | 18 | /** 19 | * Created by GensaGames 20 | * GensaGames 21 | */ 22 | 23 | public class MusicListAdapter extends RecyclerView.Adapter { 24 | 25 | private List mMusicListItems; 26 | private OnItemPlayClick mOnItemPlayClick; 27 | private Context mContext; 28 | 29 | public MusicListAdapter(Context context) { 30 | this.mMusicListItems = new LinkedList<>(); 31 | mContext = context; 32 | } 33 | 34 | @Override 35 | public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { 36 | View itemView = LayoutInflater.from(parent.getContext()) 37 | .inflate(R.layout.adapter_music_list_item, parent, false); 38 | return new MyViewHolder(itemView); 39 | } 40 | 41 | @Override 42 | public void onBindViewHolder(MyViewHolder holder, int position) { 43 | MusicListItem music = mMusicListItems.get(position); 44 | holder.mTitle.setText(music.getTitle()); 45 | holder.mDuration.setText(music.getDuration()); 46 | holder.mAuthor.setText(music.getAuthor()); 47 | if (music.isPlaying()) { 48 | holder.mImagePlay.setImageDrawable(ContextCompat.getDrawable(mContext, 49 | R.mipmap.ic_pause_circle_black_24dp)); 50 | } else { 51 | holder.mImagePlay.setImageDrawable(ContextCompat.getDrawable(mContext, 52 | R.mipmap.ic_play_circle_filled_black_24dp)); 53 | } 54 | } 55 | 56 | @Override 57 | public int getItemCount() { 58 | return mMusicListItems.size(); 59 | } 60 | 61 | public List getMusicListItems() { 62 | return mMusicListItems; 63 | } 64 | 65 | public void setOnItemPlayClick(OnItemPlayClick onItemPlayClick) { 66 | this.mOnItemPlayClick = onItemPlayClick; 67 | } 68 | 69 | public void addAll(List musicListItems) { 70 | this.mMusicListItems.addAll(musicListItems); 71 | notifyDataSetChanged(); 72 | } 73 | 74 | public void updatePlayingState(boolean state, int position) { 75 | for (MusicListItem listItem : mMusicListItems) { 76 | listItem.setIsPlaying(false); 77 | } 78 | mMusicListItems.get(position).setIsPlaying(state); 79 | notifyDataSetChanged(); 80 | } 81 | 82 | public interface OnItemPlayClick { 83 | void onItemPlayClick(int layoutPosition); 84 | } 85 | 86 | class MyViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener { 87 | 88 | private TextView mTitle, mDuration, mAuthor; 89 | private ImageView mImagePlay; 90 | 91 | private MyViewHolder(View view) { 92 | super(view); 93 | mTitle = (TextView) view.findViewById(R.id.adapter_title); 94 | mDuration = (TextView) view.findViewById(R.id.adapter_duration); 95 | mAuthor = (TextView) view.findViewById(R.id.adapter_author); 96 | mImagePlay = (ImageView) view.findViewById(R.id.adapter_image_play); 97 | mImagePlay.setOnClickListener(this); 98 | } 99 | 100 | @Override 101 | public void onClick(View view) { 102 | if (mOnItemPlayClick != null) { 103 | mOnItemPlayClick.onItemPlayClick(getLayoutPosition()); 104 | } 105 | } 106 | } 107 | } -------------------------------------------------------------------------------- /app/src/main/java/linkedlistview/sample/github/linkedlistview/controller/adapter/PlaylistPagerAdapter.java: -------------------------------------------------------------------------------- 1 | package linkedlistview.sample.github.linkedlistview.controller.adapter; 2 | 3 | 4 | import android.support.v4.app.Fragment; 5 | import android.support.v4.app.FragmentManager; 6 | import android.support.v4.app.FragmentStatePagerAdapter; 7 | 8 | import java.util.LinkedList; 9 | import java.util.List; 10 | 11 | /** 12 | * Created by GensaGames 13 | * GensaGames 14 | */ 15 | 16 | public class PlaylistPagerAdapter extends FragmentStatePagerAdapter { 17 | private List mListFragments; 18 | private List mListTitles; 19 | 20 | public PlaylistPagerAdapter(FragmentManager fragmentManager) { 21 | super(fragmentManager); 22 | mListFragments = new LinkedList<>(); 23 | mListTitles = new LinkedList<>(); 24 | } 25 | 26 | @Override 27 | public Fragment getItem(int position) { 28 | return mListFragments.get(position); 29 | } 30 | 31 | @Override 32 | public CharSequence getPageTitle(int position) { 33 | return mListTitles.get(position); 34 | } 35 | 36 | @Override 37 | public int getCount() { 38 | return mListFragments.size(); 39 | } 40 | 41 | @SuppressWarnings("unused") 42 | public void addFragment(Fragment fragment, String title) { 43 | mListFragments.add(fragment); 44 | mListTitles.add(title); 45 | } 46 | 47 | public void addAll(List fragments, List titles) { 48 | mListFragments.addAll(fragments); 49 | mListTitles.addAll(titles); 50 | } 51 | } -------------------------------------------------------------------------------- /app/src/main/java/linkedlistview/sample/github/linkedlistview/controller/animation/ActivityAnimator.java: -------------------------------------------------------------------------------- 1 | package linkedlistview.sample.github.linkedlistview.controller.animation; 2 | 3 | import android.animation.AnimatorSet; 4 | import android.animation.ObjectAnimator; 5 | import android.os.Handler; 6 | import android.os.Looper; 7 | import android.util.Log; 8 | import android.view.View; 9 | import android.view.animation.Animation; 10 | import android.view.animation.BounceInterpolator; 11 | import android.view.animation.Transformation; 12 | 13 | import java.util.ArrayList; 14 | import java.util.List; 15 | import java.util.Random; 16 | 17 | import linkedlistview.sample.github.linkedlistview.model.AnimBounceTask; 18 | import linkedlistview.sample.github.linkedlistview.model.AnimPaddingTask; 19 | 20 | /** 21 | * Created by GensaGames 22 | * GensaGames 23 | */ 24 | 25 | public class ActivityAnimator { 26 | 27 | private static final String TAG = ActivityAnimator.class.getSimpleName(); 28 | private static final long ANIM_RAND_UPPER_DUR = 12000L; 29 | private static final long ANIM_RAND_LOWER_DUR = 4000L; 30 | 31 | private Random mLocalRandom; 32 | private Handler mMainThreadHandler; 33 | private BounceInterpolator mBounceInterpolator; 34 | private List listActiveTask; 35 | private long mUpperDuration; 36 | private long mLowerDuration; 37 | 38 | public ActivityAnimator() { 39 | mMainThreadHandler = new Handler(Looper.getMainLooper()); 40 | mBounceInterpolator = new BounceInterpolator(); 41 | listActiveTask = new ArrayList<>(); 42 | mLocalRandom = new Random(); 43 | mUpperDuration = ANIM_RAND_UPPER_DUR; 44 | mLowerDuration = ANIM_RAND_LOWER_DUR; 45 | } 46 | 47 | @SuppressWarnings("unused") 48 | public void setLowerUpperDuration(long upper, long lower) { 49 | mUpperDuration = upper; 50 | mLowerDuration = lower; 51 | } 52 | 53 | private long getRandomDuration() { 54 | return mLowerDuration + (long) (mLocalRandom.nextDouble() * 55 | (mUpperDuration - mLowerDuration)); 56 | } 57 | 58 | public void animatePaddingChange(final AnimPaddingTask animPaddingTask) { 59 | final int padding[] = animPaddingTask.getPadding(); 60 | final View animatedView = animPaddingTask.getAnimatedView(); 61 | final AnimPaddingTask.OnAnimationFrame onAnimationFrame = 62 | animPaddingTask.getOnAnimationFrame(); 63 | 64 | if (padding.length != 4) { 65 | throw new IndexOutOfBoundsException("Padding requires only/least 4 Fields"); 66 | } 67 | Animation anim = new Animation() { 68 | @Override 69 | protected void applyTransformation(float interpolatedTime, Transformation t) { 70 | animatedView.setPadding((int) (padding[0] * interpolatedTime), (int) (padding[1] * 71 | interpolatedTime), (int) (padding[2] * interpolatedTime), 72 | (int) (padding[3] * interpolatedTime)); 73 | onAnimationFrame.onAnimationFrame(); 74 | } 75 | }; 76 | anim.setDuration(animPaddingTask.getDuration()); 77 | anim.setAnimationListener(animPaddingTask.getAnimationListener()); 78 | animatedView.startAnimation(anim); 79 | } 80 | 81 | public void loopRandomDelayedAnim(AnimBounceTask bounceTask) { 82 | if (listActiveTask.contains(bounceTask) || bounceTask == null) { 83 | Log.e(TAG, AnimBounceTask.class.getSimpleName() 84 | + " already work or empty!"); 85 | return; 86 | } 87 | listActiveTask.add(bounceTask); 88 | final int indexOfTask = listActiveTask.indexOf(bounceTask); 89 | mMainThreadHandler.postDelayed(new Runnable() { 90 | @Override 91 | public void run() { 92 | AnimBounceTask task = listActiveTask.get(indexOfTask); 93 | switch (task.getState()) { 94 | case START: 95 | playBounceAnimation(task.getView(), task 96 | .getMaxTranslationY(), task.getDuration()); 97 | case STOP: 98 | mMainThreadHandler.postDelayed(this, getRandomDuration()); 99 | break; 100 | case RELEASE: 101 | listActiveTask.remove(task); 102 | break; 103 | } 104 | } 105 | }, getRandomDuration()); 106 | } 107 | 108 | 109 | /** 110 | * ------------------------- *** ---------------------------- 111 | * ------------------------- *** ---------------------------- 112 | */ 113 | private AnimatorSet playBounceAnimation(View view, float maxTranslationY, long duration) { 114 | if (view == null) { 115 | Log.e(TAG, AnimBounceTask.class.getSimpleName() + " has empty View!"); 116 | return null; 117 | } 118 | float baseTranslation = view.getTranslationY(); 119 | AnimatorSet animatorSet = new AnimatorSet(); 120 | 121 | ObjectAnimator animation1 = ObjectAnimator.ofFloat(view, 122 | "translationY", maxTranslationY); 123 | animation1.setDuration(duration); 124 | animation1.setInterpolator(mBounceInterpolator); 125 | 126 | ObjectAnimator animation2 = ObjectAnimator.ofFloat(view, 127 | "translationY", baseTranslation); 128 | animation2.setDuration(duration); 129 | animation2.setInterpolator(mBounceInterpolator); 130 | 131 | animatorSet.play(animation2).after(animation1); 132 | animatorSet.start(); 133 | return animatorSet; 134 | } 135 | } 136 | -------------------------------------------------------------------------------- /app/src/main/java/linkedlistview/sample/github/linkedlistview/controller/animation/MusicHeaderAnimator.java: -------------------------------------------------------------------------------- 1 | package linkedlistview.sample.github.linkedlistview.controller.animation; 2 | 3 | import android.os.Build; 4 | import android.support.annotation.RequiresApi; 5 | import android.view.View; 6 | 7 | import com.gensagames.linkedlistview.anim.CenterMotionController; 8 | 9 | /** 10 | * Created by GensaGames 11 | * GensaGames 12 | */ 13 | 14 | public class MusicHeaderAnimator extends CenterMotionController { 15 | 16 | private float mMaxSideRotation; 17 | private boolean mSupportTranslationZ; 18 | private boolean mSupportRotationY = true; 19 | 20 | @Override 21 | public void onScrollAction() { 22 | super.onScrollAction(); 23 | 24 | if (mSupportRotationY) { 25 | for (int i = getFirstVisiblePosition() - 1; i < getLastVisiblePosition() + 1; i++) { 26 | View view = getMainViewHolder().getChildAt(i); 27 | if (view != null) { 28 | updateAngle(view); 29 | } 30 | } 31 | } 32 | 33 | if (mSupportTranslationZ) { 34 | for (int i = getFirstVisiblePosition() - 3; i < getCenterViewIndex() + 1; i++) { 35 | View view = getMainViewHolder().getChildAt(i); 36 | if (view != null) { 37 | updateTranslation(view, i, getCenterViewIndex()); 38 | } 39 | } 40 | } 41 | } 42 | 43 | @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP) 44 | public void setSupportTranslationZ(boolean supportTranslationZ) { 45 | this.mSupportTranslationZ = supportTranslationZ; 46 | } 47 | 48 | public void setSupportRotationY(boolean supportRotationY) { 49 | this.mSupportRotationY = supportRotationY; 50 | } 51 | 52 | public void setMaxSideRotation(float maxSideRotation) { 53 | this.mMaxSideRotation = maxSideRotation; 54 | } 55 | 56 | private void updateAngle(View v) { 57 | float rotationFactor = mMaxSideRotation / (getScrollViewWidth() / 2); 58 | int updated = -1 * (int) (getTotalScrollToCenter(v) * rotationFactor); 59 | v.setRotationY(updated); 60 | } 61 | 62 | private void updateTranslation(View v, int indexInVisibleQueue, int centerIndex) { 63 | if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) { 64 | return; 65 | } 66 | if (indexInVisibleQueue < centerIndex) { 67 | v.setTranslationZ(indexInVisibleQueue * -1); 68 | return; 69 | } 70 | v.setTranslationZ(0); 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /app/src/main/java/linkedlistview/sample/github/linkedlistview/model/AnimBounceTask.java: -------------------------------------------------------------------------------- 1 | package linkedlistview.sample.github.linkedlistview.model; 2 | 3 | import android.view.View; 4 | 5 | /** 6 | * Created by GensaGames 7 | * GensaGames 8 | */ 9 | 10 | public class AnimBounceTask { 11 | 12 | private View mView; 13 | private long mDuration; 14 | private float mMaxTranslationY; 15 | private State mActiveState; 16 | 17 | public AnimBounceTask(View mView, long mDuration, 18 | float mMaxTranslationY, State mActiveState) { 19 | this.mView = mView; 20 | this.mDuration = mDuration; 21 | this.mMaxTranslationY = mMaxTranslationY; 22 | this.mActiveState = mActiveState; 23 | } 24 | 25 | public View getView() { 26 | return mView; 27 | } 28 | 29 | public long getDuration() { 30 | return mDuration; 31 | } 32 | 33 | public float getMaxTranslationY() { 34 | return mMaxTranslationY; 35 | } 36 | 37 | public State getState() { 38 | return mActiveState; 39 | } 40 | 41 | public enum State { 42 | STOP, START, RELEASE 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /app/src/main/java/linkedlistview/sample/github/linkedlistview/model/AnimPaddingTask.java: -------------------------------------------------------------------------------- 1 | package linkedlistview.sample.github.linkedlistview.model; 2 | 3 | import android.support.annotation.Nullable; 4 | import android.view.View; 5 | import android.view.animation.Animation; 6 | 7 | /** 8 | * Created by GensaGames 9 | * GensaGames 10 | */ 11 | 12 | public class AnimPaddingTask { 13 | private View mAnimatedView; 14 | private long mDuration; 15 | private int[] mPadding; 16 | private Animation.AnimationListener mAnimationListener; 17 | private OnAnimationFrame mOnAnimationFrame; 18 | 19 | public AnimPaddingTask(View animatedView, long duration, int[] padding, 20 | @Nullable Animation.AnimationListener animationListener, 21 | @Nullable OnAnimationFrame onAnimationFrame) { 22 | this.mAnimatedView = animatedView; 23 | this.mDuration = duration; 24 | this.mPadding = padding; 25 | this.mAnimationListener = animationListener; 26 | this.mOnAnimationFrame = onAnimationFrame; 27 | } 28 | 29 | public View getAnimatedView() { 30 | return mAnimatedView; 31 | } 32 | 33 | public long getDuration() { 34 | return mDuration; 35 | } 36 | 37 | public int[] getPadding() { 38 | return mPadding; 39 | } 40 | 41 | public Animation.AnimationListener getAnimationListener() { 42 | return mAnimationListener; 43 | } 44 | 45 | public OnAnimationFrame getOnAnimationFrame() { 46 | return mOnAnimationFrame; 47 | } 48 | 49 | public interface OnAnimationFrame { 50 | void onAnimationFrame(); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /app/src/main/java/linkedlistview/sample/github/linkedlistview/model/MusicHeaderItem.java: -------------------------------------------------------------------------------- 1 | package linkedlistview.sample.github.linkedlistview.model; 2 | 3 | /** 4 | * Created by GensaGames 5 | * GensaGames 6 | */ 7 | 8 | public class MusicHeaderItem { 9 | private int mImageResourceId; 10 | private String mMusicName; 11 | 12 | public MusicHeaderItem(int mImageResourceId, String mMusicName) { 13 | this.mImageResourceId = mImageResourceId; 14 | this.mMusicName = mMusicName; 15 | } 16 | 17 | public int getImageResourceId() { 18 | return mImageResourceId; 19 | } 20 | 21 | public void setImageResourceId(int imageResourceId) { 22 | this.mImageResourceId = imageResourceId; 23 | } 24 | 25 | public String getMusicName() { 26 | return mMusicName; 27 | } 28 | 29 | public void setMusicName(String musicName) { 30 | this.mMusicName = musicName; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /app/src/main/java/linkedlistview/sample/github/linkedlistview/model/MusicListItem.java: -------------------------------------------------------------------------------- 1 | package linkedlistview.sample.github.linkedlistview.model; 2 | 3 | /** 4 | * Created by GensaGames 5 | * GensaGames 6 | */ 7 | 8 | public class MusicListItem { 9 | private String mTitle, mDuration, mAuthor; 10 | private boolean mIsPlaying; 11 | 12 | public MusicListItem(String title, String genre, String year) { 13 | this.mTitle = title; 14 | this.mDuration = genre; 15 | this.mAuthor = year; 16 | } 17 | 18 | public void setIsPlaying(boolean isPlaying) { 19 | this.mIsPlaying = isPlaying; 20 | } 21 | 22 | public boolean isPlaying() { 23 | return mIsPlaying; 24 | } 25 | 26 | public String getTitle() { 27 | return mTitle; 28 | } 29 | 30 | public void setTitle(String name) { 31 | this.mTitle = name; 32 | } 33 | 34 | public String getDuration() { 35 | return mDuration; 36 | } 37 | 38 | public void setDuration(String mDuration) { 39 | this.mDuration = mDuration; 40 | } 41 | 42 | public String getAuthor() { 43 | return mAuthor; 44 | } 45 | 46 | public void setAuthor(String mAuthor) { 47 | this.mAuthor = mAuthor; 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /app/src/main/java/linkedlistview/sample/github/linkedlistview/stub/StubItems.java: -------------------------------------------------------------------------------- 1 | package linkedlistview.sample.github.linkedlistview.stub; 2 | 3 | import android.support.v4.app.Fragment; 4 | 5 | import com.thedeanda.lorem.LoremIpsum; 6 | 7 | import java.util.ArrayList; 8 | import java.util.List; 9 | import java.util.Random; 10 | 11 | import linkedlistview.sample.github.linkedlistview.R; 12 | import linkedlistview.sample.github.linkedlistview.model.MusicHeaderItem; 13 | import linkedlistview.sample.github.linkedlistview.model.MusicListItem; 14 | import linkedlistview.sample.github.linkedlistview.view.FragmentPlaylist; 15 | 16 | /** 17 | * Created by GensaGames 18 | * GensaGames 19 | */ 20 | 21 | public class StubItems { 22 | 23 | /** 24 | * TODO(Dimens) Optimize Const below 25 | * In scope of device resolutions support 26 | * For now, it's only for Nexus 4 (API 23 768 - 1280) 27 | */ 28 | public static final int VU_METER_ITEMS = 7; 29 | public static final int OPT_LINKEDLIST_OVERLAP = -40; 30 | public static final int MAX_LINKEDLIST_ROTATION = 40; 31 | public static final int MAX_LINKEDLIST_TRANSLATION = 120; 32 | 33 | /** 34 | * ---------------------- *** --------------------------- 35 | *----------------------- *** --------------------------- 36 | */ 37 | 38 | public static final String SAMPLE_MUSIC_1 = "sample_song_1"; 39 | public static final String SAMPLE_MUSIC_FOLDER = "raw"; 40 | 41 | public static final long ANIM_LINKEDLIST_BOUNDS = 1000L; 42 | public static final long ANIM_LINKEDLIST_SELECT = 500L; 43 | public static final long ANIM_STAR_BOUND_DUR = 400L; 44 | public static final long DELAY_BASE_ANIM_INIT = 500L; 45 | 46 | public static final float MIN_VUMETER_SCALE = 0.6f; 47 | public static final float MAX_VUMETER_TRANSLATE = -60f; 48 | public static final float MAX_HEADER_BAR_SCALE = 0.8f; 49 | public static final float MAX_SCROLL_HIDE_BAR = 0.45f; 50 | 51 | private static final int PLAYLIST_ITEMS_MIN = 10; 52 | private static final int PLAYLIST_ITEMS_MAX = 15; 53 | private static final int PLAYLIST_COUNT = 3; 54 | 55 | private static final int[] MUSIC_PHOTOS = {R.drawable.music_album_photo_2, R.drawable.music_album_photo_3, 56 | R.drawable.music_album_photo_4, R.drawable.music_album_photo_5, R.drawable.music_album_photo_6, 57 | R.drawable.music_album_photo_7, R.drawable.music_album_photo_8, R.drawable.music_album_photo_9, 58 | R.drawable.music_album_photo_10, R.drawable.music_album_photo_11, R.drawable.music_album_photo_12, 59 | R.drawable.music_album_photo_13, R.drawable.music_album_photo_14, R.drawable.music_album_photo_15, 60 | R.drawable.music_album_photo_16, R.drawable.music_album_photo_17, R.drawable.music_album_photo_18, 61 | R.drawable.music_album_photo_19, R.drawable.music_album_photo_20, R.drawable.music_album_photo_21, 62 | R.drawable.music_album_photo_22}; 63 | 64 | public static List getBaseMusicItems() { 65 | List items = new ArrayList<>(); 66 | for (int resId : MUSIC_PHOTOS) { 67 | items.add(new MusicHeaderItem(resId, LoremIpsum.getInstance().getName())); 68 | } 69 | return items; 70 | } 71 | 72 | public static List getBasePlaylistFragments() { 73 | List fragments = new ArrayList<>(); 74 | for (int i = 0; i < PLAYLIST_COUNT; i++) { 75 | fragments.add(new FragmentPlaylist()); 76 | } 77 | return fragments; 78 | } 79 | 80 | public static List getBasePlaylistTitles() { 81 | List titles = new ArrayList<>(); 82 | for (int i = 0; i < PLAYLIST_COUNT; i++) { 83 | titles.add(LoremIpsum.getInstance().getWords(2)); 84 | } 85 | return titles; 86 | } 87 | 88 | public static List getBasePlaylistMusicItems() { 89 | List musicListItems = new ArrayList<>(); 90 | Random random = new Random(); 91 | int randomCount = random.nextInt((PLAYLIST_ITEMS_MAX - 92 | PLAYLIST_ITEMS_MIN) + 1) + PLAYLIST_ITEMS_MIN; 93 | for (int i = 0; i < randomCount; i++) { 94 | String time = random.nextInt(50) + ":" + random.nextInt(59); 95 | musicListItems.add(new MusicListItem(LoremIpsum.getInstance().getTitle(3, 4), time, 96 | LoremIpsum.getInstance().getName())); 97 | } 98 | return musicListItems; 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /app/src/main/java/linkedlistview/sample/github/linkedlistview/view/ActivityMainPlay.java: -------------------------------------------------------------------------------- 1 | package linkedlistview.sample.github.linkedlistview.view; 2 | 3 | import android.Manifest; 4 | import android.media.AudioManager; 5 | import android.media.MediaPlayer; 6 | import android.os.Build; 7 | import android.os.Bundle; 8 | import android.os.Handler; 9 | import android.os.Looper; 10 | import android.support.annotation.Nullable; 11 | import android.support.design.widget.AppBarLayout; 12 | import android.support.design.widget.FloatingActionButton; 13 | import android.support.design.widget.TabLayout; 14 | import android.support.v4.app.AppLaunchChecker; 15 | import android.support.v4.content.ContextCompat; 16 | import android.support.v4.view.ViewCompat; 17 | import android.support.v4.view.ViewPager; 18 | import android.support.v7.widget.Toolbar; 19 | import android.util.Log; 20 | import android.view.View; 21 | import android.widget.LinearLayout; 22 | 23 | import com.cleveroad.audiovisualization.DbmHandler; 24 | import com.cleveroad.audiovisualization.GLAudioVisualizationView; 25 | import com.cleveroad.audiovisualization.VisualizerDbmHandler; 26 | import com.gensagames.linkedlistview.LinkedListView; 27 | import com.thedeanda.lorem.LoremIpsum; 28 | 29 | import java.util.ArrayList; 30 | import java.util.Arrays; 31 | import java.util.List; 32 | 33 | import butterknife.BindView; 34 | import butterknife.ButterKnife; 35 | import butterknife.OnClick; 36 | import io.gresse.hugo.vumeterlibrary.VuMeterView; 37 | import linkedlistview.sample.github.linkedlistview.R; 38 | import linkedlistview.sample.github.linkedlistview.controller.adapter.MusicHeaderAdapter; 39 | import linkedlistview.sample.github.linkedlistview.controller.adapter.PlaylistPagerAdapter; 40 | import linkedlistview.sample.github.linkedlistview.controller.animation.ActivityAnimator; 41 | import linkedlistview.sample.github.linkedlistview.controller.animation.MusicHeaderAnimator; 42 | import linkedlistview.sample.github.linkedlistview.model.AnimBounceTask; 43 | import linkedlistview.sample.github.linkedlistview.model.AnimPaddingTask; 44 | import linkedlistview.sample.github.linkedlistview.stub.StubItems; 45 | import linkedlistview.sample.github.linkedlistview.view.base.BaseActivity; 46 | 47 | public class ActivityMainPlay extends BaseActivity implements LinkedListView.OnItemClickListener, 48 | AppBarLayout.OnOffsetChangedListener { 49 | 50 | @SuppressWarnings("unused") 51 | private static final String TAG = ActivityMainPlay.class.getSimpleName(); 52 | 53 | @BindView(R.id.header_toolbar) 54 | public Toolbar mMainToolbar; 55 | 56 | @BindView(R.id.header_vumeter) 57 | public VuMeterView mVuMeterView; 58 | 59 | @BindView(R.id.header_visualizer_view) 60 | public GLAudioVisualizationView mVisualWaves; 61 | 62 | @BindView(R.id.header_appbar) 63 | public AppBarLayout mAppBarLayout; 64 | 65 | @BindView(R.id.header_tab_layout) 66 | public TabLayout mTabLayout; 67 | 68 | @BindView(R.id.header_fab) 69 | public FloatingActionButton mMainFab; 70 | 71 | @BindView(R.id.header_bar_previous) 72 | public FloatingActionButton mBarPrevious; 73 | 74 | @BindView(R.id.header_bar_star) 75 | public FloatingActionButton mBarStar; 76 | 77 | @BindView(R.id.header_bar_next) 78 | public FloatingActionButton mBarNext; 79 | 80 | @BindView(R.id.header_button_bar) 81 | public LinearLayout mHeaderBarLayout; 82 | 83 | @BindView(R.id.content_linkedlistview) 84 | public LinkedListView mLinkedListView; 85 | 86 | @BindView(R.id.content_viewpager) 87 | public ViewPager mViewPager; 88 | 89 | private MediaPlayer mMediaPlayer; 90 | private MusicHeaderAdapter mMusicHeaderAdapter; 91 | private MusicHeaderAnimator mMusicHeaderAnimator; 92 | 93 | @SuppressWarnings("FieldCanBeLocal") 94 | private PlaylistPagerAdapter mPlaylistPagerAdapter; 95 | private ActivityAnimator activityAnimator; 96 | private boolean mIsHeaderBarHidden; 97 | 98 | @Override 99 | protected void onCreate(Bundle savedInstanceState) { 100 | super.onCreate(savedInstanceState); 101 | setContentView(R.layout.activity_main_header); 102 | ButterKnife.bind(this); 103 | 104 | setupToolbar(); 105 | setupLinkedList(); 106 | setupViewPager(); 107 | setupMediaPlayer(); 108 | } 109 | 110 | @Override 111 | public void onResume() { 112 | super.onResume(); 113 | mVisualWaves.onResume(); 114 | } 115 | 116 | @Override 117 | public void onPause() { 118 | mVisualWaves.onPause(); 119 | super.onPause(); 120 | } 121 | 122 | @Override 123 | public void onDestroy() { 124 | super.onDestroy(); 125 | mVisualWaves.release(); 126 | mMediaPlayer.release(); 127 | } 128 | 129 | @Override 130 | public void onFirstFocusedStart() { 131 | Log.e(TAG, "onFirstFocusedStart: "); 132 | new Handler(Looper.getMainLooper()).postDelayed(new Runnable() { 133 | @Override 134 | public void run() { 135 | checkActivityPermissions(); 136 | starAnimDispatcher(); 137 | updateListBounds(); 138 | } 139 | }, StubItems.DELAY_BASE_ANIM_INIT); 140 | } 141 | 142 | @Override 143 | public void onOffsetChanged(AppBarLayout appBarLayout, int verticalOffset) { 144 | float currentScrollPercentage = (float) Math.abs(verticalOffset) 145 | / appBarLayout.getTotalScrollRange(); 146 | updateToolbarScroll(currentScrollPercentage); 147 | } 148 | 149 | @Override 150 | public void onItemClick(View view) { 151 | mMusicHeaderAnimator.animateScrollTo(view, StubItems.ANIM_LINKEDLIST_SELECT); 152 | Log.e(TAG, "onItemClick: " + view.getId()); 153 | } 154 | 155 | @Override 156 | public ArrayList requiredPermissions() { 157 | return new ArrayList<>(Arrays.asList(Manifest.permission.RECORD_AUDIO, 158 | Manifest.permission.MODIFY_AUDIO_SETTINGS)); 159 | } 160 | 161 | @Override 162 | public void onPermissionsGranted() { 163 | updateToolbarVisualizer(); 164 | } 165 | 166 | @Override 167 | public void onPermissionsDenied(List deniedPermissionList) { 168 | /**------------------------- 169 | * TODO(Permission): ROFL 170 | * -----------------------*/ 171 | } 172 | 173 | @SuppressWarnings("unused") 174 | @OnClick(R.id.header_fab) 175 | public void onClickPlayFab() { 176 | updatePlayState(!mMediaPlayer.isPlaying()); 177 | } 178 | 179 | @SuppressWarnings("unused") 180 | @OnClick(R.id.header_bar_next) 181 | public void onClickNextFab() { 182 | selectHeaderMusicItem(1); 183 | } 184 | 185 | @SuppressWarnings("unused") 186 | @OnClick(R.id.header_bar_previous) 187 | public void onClickPreviousFab() { 188 | selectHeaderMusicItem(-1); 189 | } 190 | 191 | 192 | private void setupToolbar() { 193 | mMainToolbar.setTitle(LoremIpsum.getInstance().getWords(3, 5)); 194 | mVuMeterView.setBlockNumber(StubItems.VU_METER_ITEMS); 195 | mVuMeterView.stop(false); 196 | mHeaderBarLayout.setScaleX(0); 197 | mHeaderBarLayout.setScaleY(0); 198 | mAppBarLayout.addOnOffsetChangedListener(this); 199 | mAppBarLayout.setExpanded(false, false); 200 | setSupportActionBar(mMainToolbar); 201 | } 202 | 203 | private void setupMediaPlayer() { 204 | int sampleSongLocation = getResources().getIdentifier(StubItems.SAMPLE_MUSIC_1, 205 | StubItems.SAMPLE_MUSIC_FOLDER, getPackageName()); 206 | mMediaPlayer = MediaPlayer.create(ActivityMainPlay.this, sampleSongLocation); 207 | mMediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC); 208 | mMediaPlayer.setLooping(true); 209 | } 210 | 211 | private void starAnimDispatcher() { 212 | activityAnimator = new ActivityAnimator(); 213 | activityAnimator.loopRandomDelayedAnim(new AnimBounceTask(mBarStar, 214 | StubItems.ANIM_STAR_BOUND_DUR, (mBarStar.getWidth() / 3), 215 | AnimBounceTask.State.START)); 216 | } 217 | 218 | private void setupViewPager() { 219 | mPlaylistPagerAdapter = new PlaylistPagerAdapter(getSupportFragmentManager()); 220 | mPlaylistPagerAdapter.addAll(StubItems.getBasePlaylistFragments(), 221 | StubItems.getBasePlaylistTitles()); 222 | 223 | mTabLayout.setupWithViewPager(mViewPager, true); 224 | mViewPager.setAdapter(mPlaylistPagerAdapter); 225 | } 226 | 227 | private void setupLinkedList() { 228 | mMusicHeaderAdapter = new MusicHeaderAdapter(getApplicationContext()); 229 | mMusicHeaderAdapter.addItemList(StubItems.getBaseMusicItems()); 230 | mMusicHeaderAdapter.setOnItemClickListener(this); 231 | mLinkedListView.setAdapter(mMusicHeaderAdapter); 232 | 233 | mMusicHeaderAnimator = new MusicHeaderAnimator(); 234 | mMusicHeaderAnimator.setMaxSideRotation(StubItems.MAX_LINKEDLIST_ROTATION); 235 | mMusicHeaderAnimator.setMaxTranslationX(StubItems.MAX_LINKEDLIST_TRANSLATION); 236 | mMusicHeaderAnimator.setOptLeftOverlap(StubItems.OPT_LINKEDLIST_OVERLAP); 237 | mMusicHeaderAnimator.setOptRightOverlap(StubItems.OPT_LINKEDLIST_OVERLAP); 238 | mMusicHeaderAnimator.setSupportRotationY(true); 239 | mLinkedListView.setAnimationController(mMusicHeaderAnimator); 240 | 241 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { 242 | mMusicHeaderAnimator.setSupportTranslationZ(true); 243 | } 244 | } 245 | 246 | private void selectHeaderMusicItem(int indexChange) { 247 | int index = mMusicHeaderAnimator.getCenterViewIndex() + indexChange; 248 | if (index < 0 || index >= mMusicHeaderAdapter.getObjectCount()) { 249 | return; 250 | } 251 | Log.e("Ind", "Index: " + index); 252 | mMusicHeaderAnimator.animateScrollTo(mLinkedListView.getMainViewHolder() 253 | .getChildAt(index), StubItems.ANIM_LINKEDLIST_SELECT); 254 | } 255 | 256 | private void updateToolbarScroll(float scrollPercentage) { 257 | float differenceScale = 1 - StubItems.MIN_VUMETER_SCALE; 258 | float updatedScale = StubItems.MIN_VUMETER_SCALE + 259 | ((1 - scrollPercentage) * differenceScale); 260 | mVuMeterView.setScaleX(updatedScale); 261 | mVuMeterView.setScaleY(updatedScale); 262 | 263 | float maxTranslateX = StubItems.MAX_VUMETER_TRANSLATE; 264 | float updatedTranslate = scrollPercentage * maxTranslateX; 265 | mVuMeterView.setTranslationX(updatedTranslate); 266 | 267 | if (scrollPercentage > StubItems.MAX_SCROLL_HIDE_BAR) { 268 | if (!mIsHeaderBarHidden) { 269 | mIsHeaderBarHidden = true; 270 | ViewCompat.animate(mHeaderBarLayout).scaleY(0).scaleX(0).start(); 271 | } 272 | } else { 273 | if (mIsHeaderBarHidden) { 274 | mIsHeaderBarHidden = false; 275 | ViewCompat.animate(mHeaderBarLayout).scaleY(StubItems.MAX_HEADER_BAR_SCALE) 276 | .scaleX(StubItems.MAX_HEADER_BAR_SCALE).start(); 277 | } 278 | } 279 | } 280 | 281 | public void updatePlayState(boolean play) { 282 | if (mMediaPlayer.isPlaying()) { 283 | if (play) { 284 | return; 285 | } 286 | mMediaPlayer.pause(); 287 | mVuMeterView.stop(true); 288 | mMainFab.setImageDrawable(ContextCompat.getDrawable(ActivityMainPlay.this, 289 | android.R.drawable.ic_media_play)); 290 | } else { 291 | if (!play) { 292 | return; 293 | } 294 | mMediaPlayer.start(); 295 | mVuMeterView.resume(true); 296 | mMusicHeaderAnimator.animateScrollTo(mLinkedListView.getMainViewHolder() 297 | .getChildAt(mMusicHeaderAnimator.getCenterViewIndex()), StubItems 298 | .ANIM_LINKEDLIST_SELECT); 299 | mMainFab.setImageDrawable(ContextCompat.getDrawable(ActivityMainPlay.this, 300 | android.R.drawable.ic_media_pause)); 301 | } 302 | } 303 | 304 | private void updateToolbarVisualizer() { 305 | VisualizerDbmHandler visualizerHandler = DbmHandler.Factory 306 | .newVisualizerHandler(ActivityMainPlay.this, mMediaPlayer); 307 | mVisualWaves.linkTo(visualizerHandler); 308 | visualizerHandler.onResume(); 309 | } 310 | 311 | private void updateListBounds() { 312 | mAppBarLayout.setExpanded(true, true); 313 | int sidePadding = mLinkedListView.getWidth() / 2 - mLinkedListView 314 | .getPaddingStart() - mLinkedListView.getPaddingEnd(); 315 | int padding[] = new int[]{sidePadding, 0, sidePadding, 0}; 316 | AnimPaddingTask animPaddingTask = new AnimPaddingTask(mLinkedListView.getMainViewHolder(), 317 | StubItems.ANIM_LINKEDLIST_BOUNDS, padding, null, new AnimPaddingTask.OnAnimationFrame() { 318 | @Override 319 | public void onAnimationFrame() { 320 | mLinkedListView.onScrollChanged(); 321 | } 322 | }); 323 | activityAnimator.animatePaddingChange(animPaddingTask); 324 | } 325 | 326 | 327 | } 328 | -------------------------------------------------------------------------------- /app/src/main/java/linkedlistview/sample/github/linkedlistview/view/ActivitySplash.java: -------------------------------------------------------------------------------- 1 | package linkedlistview.sample.github.linkedlistview.view; 2 | 3 | import android.content.Intent; 4 | import android.os.Handler; 5 | import android.os.Looper; 6 | import android.support.v7.app.AppCompatActivity; 7 | import android.os.Bundle; 8 | 9 | import linkedlistview.sample.github.linkedlistview.R; 10 | 11 | public class ActivitySplash extends AppCompatActivity { 12 | 13 | private static final long DELAY_SPLASH_SCREEN = 1200L; 14 | @Override 15 | protected void onCreate(Bundle savedInstanceState) { 16 | super.onCreate(savedInstanceState); 17 | setContentView(R.layout.activity_splash); 18 | 19 | /** 20 | * This just to avoid white screen, during loading and 21 | * saving state for permission checking. 22 | */ 23 | new Handler(Looper.getMainLooper()).postDelayed(new Runnable() { 24 | @Override 25 | public void run() { 26 | startActivity(new Intent(getApplicationContext(), ActivityMainPlay.class)); 27 | } 28 | }, DELAY_SPLASH_SCREEN); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /app/src/main/java/linkedlistview/sample/github/linkedlistview/view/FragmentPlaylist.java: -------------------------------------------------------------------------------- 1 | package linkedlistview.sample.github.linkedlistview.view; 2 | 3 | import android.os.Bundle; 4 | import android.support.annotation.Nullable; 5 | import android.support.v4.app.Fragment; 6 | import android.support.v7.widget.DefaultItemAnimator; 7 | import android.support.v7.widget.LinearLayoutManager; 8 | import android.support.v7.widget.RecyclerView; 9 | import android.view.LayoutInflater; 10 | import android.view.View; 11 | import android.view.ViewGroup; 12 | 13 | import java.util.List; 14 | 15 | import butterknife.BindView; 16 | import butterknife.ButterKnife; 17 | import linkedlistview.sample.github.linkedlistview.R; 18 | import linkedlistview.sample.github.linkedlistview.controller.adapter.MusicListAdapter; 19 | import linkedlistview.sample.github.linkedlistview.model.MusicListItem; 20 | import linkedlistview.sample.github.linkedlistview.stub.StubItems; 21 | 22 | /** 23 | * Created by GensaGames 24 | * GensaGames 25 | */ 26 | 27 | public class FragmentPlaylist extends Fragment implements MusicListAdapter.OnItemPlayClick { 28 | 29 | @BindView(R.id.content_recyclerview) 30 | public RecyclerView mRecyclerView; 31 | 32 | private MusicListAdapter mMusicListAdapter; 33 | 34 | @Override 35 | public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { 36 | return inflater.inflate(R.layout.fragment_playlist, container, false); 37 | } 38 | 39 | @Override 40 | public void onViewCreated(View view, @Nullable Bundle savedInstanceState) { 41 | super.onViewCreated(view, savedInstanceState); 42 | ButterKnife.bind(this, view); 43 | setupRecyclerView(); 44 | } 45 | 46 | private void setupRecyclerView() { 47 | mMusicListAdapter = new MusicListAdapter(getContext()); 48 | mMusicListAdapter.addAll(StubItems.getBasePlaylistMusicItems()); 49 | mMusicListAdapter.setOnItemPlayClick(this); 50 | mRecyclerView.setLayoutManager(new LinearLayoutManager(getActivity())); 51 | mRecyclerView.setItemAnimator(new DefaultItemAnimator()); 52 | mRecyclerView.setAdapter(mMusicListAdapter); 53 | } 54 | 55 | @Override 56 | public void onItemPlayClick(int layoutPosition) { 57 | List musicListItems = mMusicListAdapter.getMusicListItems(); 58 | boolean itemIsNotPlaying = !musicListItems.get(layoutPosition).isPlaying(); 59 | mMusicListAdapter.updatePlayingState(itemIsNotPlaying, layoutPosition); 60 | ((ActivityMainPlay) getActivity()).updatePlayState(itemIsNotPlaying); 61 | 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /app/src/main/java/linkedlistview/sample/github/linkedlistview/view/base/BaseActivity.java: -------------------------------------------------------------------------------- 1 | package linkedlistview.sample.github.linkedlistview.view.base; 2 | 3 | import android.content.pm.PackageManager; 4 | import android.os.Bundle; 5 | import android.support.annotation.NonNull; 6 | import android.support.annotation.Nullable; 7 | import android.support.v4.app.ActivityCompat; 8 | import android.support.v4.app.AppLaunchChecker; 9 | import android.support.v4.content.ContextCompat; 10 | import android.support.v7.app.AppCompatActivity; 11 | import android.util.Log; 12 | 13 | import java.util.ArrayList; 14 | import java.util.List; 15 | 16 | import linkedlistview.sample.github.linkedlistview.view.helper.FirstFocusedStartListener; 17 | 18 | /** 19 | * Created by GensaGames 20 | * GensaGames 21 | */ 22 | 23 | public abstract class BaseActivity extends AppCompatActivity implements FirstFocusedStartListener { 24 | 25 | @SuppressWarnings("unused") 26 | private static final String TAG = BaseActivity.class.getSimpleName(); 27 | private static final int PERMISSION_REQUEST_CODE = 101; 28 | private boolean mIsFirstStart; 29 | 30 | 31 | @Override 32 | protected void onCreate(@Nullable Bundle savedInstanceState) { 33 | super.onCreate(savedInstanceState); 34 | mIsFirstStart = !mIsFirstStart; 35 | } 36 | 37 | @Override 38 | public void onWindowFocusChanged(boolean hasWindowFocus) { 39 | super.onWindowFocusChanged(hasWindowFocus); 40 | if (hasWindowFocus && mIsFirstStart) { 41 | mIsFirstStart = false; 42 | onFirstFocusedStart(); 43 | } 44 | } 45 | 46 | @Override 47 | public void onRequestPermissionsResult(int requestCode, @NonNull String permissions[], 48 | @NonNull int[] grantResults) { 49 | if (requestCode != PERMISSION_REQUEST_CODE) { 50 | return; 51 | } 52 | List deniedPermission = null; 53 | for (int i = 0; i < permissions.length; i++) { 54 | if (grantResults[i] != PackageManager.PERMISSION_GRANTED) { 55 | if (deniedPermission == null) 56 | deniedPermission = new ArrayList<>(); 57 | deniedPermission.add(permissions[i]); 58 | } 59 | } 60 | if (deniedPermission != null) { 61 | onPermissionsDenied(deniedPermission); 62 | return; 63 | } 64 | onPermissionsGranted(); 65 | } 66 | 67 | public void checkActivityPermissions() { 68 | List requiresListPermission = requiredPermissions(); 69 | if (requiresListPermission == null || requiresListPermission.isEmpty()) { 70 | return; 71 | } 72 | List grantedListPermissions = new ArrayList<>(); 73 | for (String permission : requiresListPermission) { 74 | int permissionStatus = ContextCompat.checkSelfPermission(this, permission); 75 | if (permissionStatus == PackageManager.PERMISSION_GRANTED) { 76 | grantedListPermissions.add(permission); 77 | } 78 | } 79 | requiresListPermission.removeAll(grantedListPermissions); 80 | if (!requiresListPermission.isEmpty()) { 81 | makeRequest(requiresListPermission); 82 | return; 83 | } 84 | onPermissionsGranted(); 85 | } 86 | 87 | 88 | protected void makeRequest(List permissionsList) { 89 | ActivityCompat.requestPermissions(this, permissionsList 90 | .toArray(new String[permissionsList.size()]), PERMISSION_REQUEST_CODE); 91 | } 92 | 93 | public abstract ArrayList requiredPermissions(); 94 | 95 | public abstract void onPermissionsDenied(List deniedPermissions); 96 | 97 | public abstract void onPermissionsGranted(); 98 | } 99 | -------------------------------------------------------------------------------- /app/src/main/java/linkedlistview/sample/github/linkedlistview/view/helper/FirstFocusedStartListener.java: -------------------------------------------------------------------------------- 1 | package linkedlistview.sample.github.linkedlistview.view.helper; 2 | 3 | /** 4 | * Created by GensaGames 5 | * GensaGames 6 | */ 7 | 8 | public interface FirstFocusedStartListener { 9 | void onFirstFocusedStart(); 10 | } 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/music_album_photo_1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GensaGames/Sample-LinkedListView/22e3de0d6411c4d030ba148b60658e72d559e09e/app/src/main/res/drawable/music_album_photo_1.jpg -------------------------------------------------------------------------------- /app/src/main/res/drawable/music_album_photo_10.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GensaGames/Sample-LinkedListView/22e3de0d6411c4d030ba148b60658e72d559e09e/app/src/main/res/drawable/music_album_photo_10.jpg -------------------------------------------------------------------------------- /app/src/main/res/drawable/music_album_photo_11.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GensaGames/Sample-LinkedListView/22e3de0d6411c4d030ba148b60658e72d559e09e/app/src/main/res/drawable/music_album_photo_11.jpg -------------------------------------------------------------------------------- /app/src/main/res/drawable/music_album_photo_12.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GensaGames/Sample-LinkedListView/22e3de0d6411c4d030ba148b60658e72d559e09e/app/src/main/res/drawable/music_album_photo_12.jpg -------------------------------------------------------------------------------- /app/src/main/res/drawable/music_album_photo_13.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GensaGames/Sample-LinkedListView/22e3de0d6411c4d030ba148b60658e72d559e09e/app/src/main/res/drawable/music_album_photo_13.jpg -------------------------------------------------------------------------------- /app/src/main/res/drawable/music_album_photo_14.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GensaGames/Sample-LinkedListView/22e3de0d6411c4d030ba148b60658e72d559e09e/app/src/main/res/drawable/music_album_photo_14.jpg -------------------------------------------------------------------------------- /app/src/main/res/drawable/music_album_photo_15.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GensaGames/Sample-LinkedListView/22e3de0d6411c4d030ba148b60658e72d559e09e/app/src/main/res/drawable/music_album_photo_15.jpg -------------------------------------------------------------------------------- /app/src/main/res/drawable/music_album_photo_16.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GensaGames/Sample-LinkedListView/22e3de0d6411c4d030ba148b60658e72d559e09e/app/src/main/res/drawable/music_album_photo_16.jpg -------------------------------------------------------------------------------- /app/src/main/res/drawable/music_album_photo_17.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GensaGames/Sample-LinkedListView/22e3de0d6411c4d030ba148b60658e72d559e09e/app/src/main/res/drawable/music_album_photo_17.jpg -------------------------------------------------------------------------------- /app/src/main/res/drawable/music_album_photo_18.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GensaGames/Sample-LinkedListView/22e3de0d6411c4d030ba148b60658e72d559e09e/app/src/main/res/drawable/music_album_photo_18.jpg -------------------------------------------------------------------------------- /app/src/main/res/drawable/music_album_photo_19.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GensaGames/Sample-LinkedListView/22e3de0d6411c4d030ba148b60658e72d559e09e/app/src/main/res/drawable/music_album_photo_19.jpg -------------------------------------------------------------------------------- /app/src/main/res/drawable/music_album_photo_2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GensaGames/Sample-LinkedListView/22e3de0d6411c4d030ba148b60658e72d559e09e/app/src/main/res/drawable/music_album_photo_2.jpg -------------------------------------------------------------------------------- /app/src/main/res/drawable/music_album_photo_20.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GensaGames/Sample-LinkedListView/22e3de0d6411c4d030ba148b60658e72d559e09e/app/src/main/res/drawable/music_album_photo_20.jpg -------------------------------------------------------------------------------- /app/src/main/res/drawable/music_album_photo_21.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GensaGames/Sample-LinkedListView/22e3de0d6411c4d030ba148b60658e72d559e09e/app/src/main/res/drawable/music_album_photo_21.jpg -------------------------------------------------------------------------------- /app/src/main/res/drawable/music_album_photo_22.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GensaGames/Sample-LinkedListView/22e3de0d6411c4d030ba148b60658e72d559e09e/app/src/main/res/drawable/music_album_photo_22.jpg -------------------------------------------------------------------------------- /app/src/main/res/drawable/music_album_photo_3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GensaGames/Sample-LinkedListView/22e3de0d6411c4d030ba148b60658e72d559e09e/app/src/main/res/drawable/music_album_photo_3.jpg -------------------------------------------------------------------------------- /app/src/main/res/drawable/music_album_photo_4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GensaGames/Sample-LinkedListView/22e3de0d6411c4d030ba148b60658e72d559e09e/app/src/main/res/drawable/music_album_photo_4.jpg -------------------------------------------------------------------------------- /app/src/main/res/drawable/music_album_photo_5.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GensaGames/Sample-LinkedListView/22e3de0d6411c4d030ba148b60658e72d559e09e/app/src/main/res/drawable/music_album_photo_5.jpg -------------------------------------------------------------------------------- /app/src/main/res/drawable/music_album_photo_6.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GensaGames/Sample-LinkedListView/22e3de0d6411c4d030ba148b60658e72d559e09e/app/src/main/res/drawable/music_album_photo_6.jpg -------------------------------------------------------------------------------- /app/src/main/res/drawable/music_album_photo_7.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GensaGames/Sample-LinkedListView/22e3de0d6411c4d030ba148b60658e72d559e09e/app/src/main/res/drawable/music_album_photo_7.jpg -------------------------------------------------------------------------------- /app/src/main/res/drawable/music_album_photo_8.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GensaGames/Sample-LinkedListView/22e3de0d6411c4d030ba148b60658e72d559e09e/app/src/main/res/drawable/music_album_photo_8.jpg -------------------------------------------------------------------------------- /app/src/main/res/drawable/music_album_photo_9.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GensaGames/Sample-LinkedListView/22e3de0d6411c4d030ba148b60658e72d559e09e/app/src/main/res/drawable/music_album_photo_9.jpg -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_main_content.xml: -------------------------------------------------------------------------------- 1 | 2 | 11 | 12 | 16 | 17 | 25 | 26 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_main_header.xml: -------------------------------------------------------------------------------- 1 | 2 | 10 | 11 | 17 | 18 | 27 | 28 | 29 | 42 | 43 | 49 | 50 | 53 | 54 | 55 | 56 | 64 | 65 | 76 | 77 | 86 | 87 | 99 | 100 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 120 | 121 | 134 | 135 | 145 | 146 | 147 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_splash.xml: -------------------------------------------------------------------------------- 1 | 2 | 11 | 12 | 19 | 20 | -------------------------------------------------------------------------------- /app/src/main/res/layout/adapter_music_header_item.xml: -------------------------------------------------------------------------------- 1 | 6 | 7 | 8 | 15 | 16 | 24 | 25 | -------------------------------------------------------------------------------- /app/src/main/res/layout/adapter_music_list_item.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 12 | 13 | 14 | 21 | 22 | 26 | 27 | 32 | 33 | 41 | 42 | 46 | 47 | 54 | 55 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 78 | 79 | 80 | 81 | 82 | 83 | -------------------------------------------------------------------------------- /app/src/main/res/layout/fragment_playlist.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 14 | 15 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GensaGames/Sample-LinkedListView/22e3de0d6411c4d030ba148b60658e72d559e09e/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_pause_circle_black_24dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GensaGames/Sample-LinkedListView/22e3de0d6411c4d030ba148b60658e72d559e09e/app/src/main/res/mipmap-hdpi/ic_pause_circle_black_24dp.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_play_circle_filled_black_24dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GensaGames/Sample-LinkedListView/22e3de0d6411c4d030ba148b60658e72d559e09e/app/src/main/res/mipmap-hdpi/ic_play_circle_filled_black_24dp.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_skip_next_circle_black_24dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GensaGames/Sample-LinkedListView/22e3de0d6411c4d030ba148b60658e72d559e09e/app/src/main/res/mipmap-hdpi/ic_skip_next_circle_black_24dp.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_skip_previous_circle_black_24dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GensaGames/Sample-LinkedListView/22e3de0d6411c4d030ba148b60658e72d559e09e/app/src/main/res/mipmap-hdpi/ic_skip_previous_circle_black_24dp.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_star_black_24dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GensaGames/Sample-LinkedListView/22e3de0d6411c4d030ba148b60658e72d559e09e/app/src/main/res/mipmap-hdpi/ic_star_black_24dp.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GensaGames/Sample-LinkedListView/22e3de0d6411c4d030ba148b60658e72d559e09e/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/ic_pause_circle_black_24dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GensaGames/Sample-LinkedListView/22e3de0d6411c4d030ba148b60658e72d559e09e/app/src/main/res/mipmap-mdpi/ic_pause_circle_black_24dp.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/ic_play_circle_filled_black_24dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GensaGames/Sample-LinkedListView/22e3de0d6411c4d030ba148b60658e72d559e09e/app/src/main/res/mipmap-mdpi/ic_play_circle_filled_black_24dp.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/ic_skip_next_circle_black_24dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GensaGames/Sample-LinkedListView/22e3de0d6411c4d030ba148b60658e72d559e09e/app/src/main/res/mipmap-mdpi/ic_skip_next_circle_black_24dp.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/ic_skip_previous_circle_black_24dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GensaGames/Sample-LinkedListView/22e3de0d6411c4d030ba148b60658e72d559e09e/app/src/main/res/mipmap-mdpi/ic_skip_previous_circle_black_24dp.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/ic_star_black_24dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GensaGames/Sample-LinkedListView/22e3de0d6411c4d030ba148b60658e72d559e09e/app/src/main/res/mipmap-mdpi/ic_star_black_24dp.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GensaGames/Sample-LinkedListView/22e3de0d6411c4d030ba148b60658e72d559e09e/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_pause_circle_black_24dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GensaGames/Sample-LinkedListView/22e3de0d6411c4d030ba148b60658e72d559e09e/app/src/main/res/mipmap-xhdpi/ic_pause_circle_black_24dp.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_play_circle_filled_black_24dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GensaGames/Sample-LinkedListView/22e3de0d6411c4d030ba148b60658e72d559e09e/app/src/main/res/mipmap-xhdpi/ic_play_circle_filled_black_24dp.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_skip_next_circle_black_24dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GensaGames/Sample-LinkedListView/22e3de0d6411c4d030ba148b60658e72d559e09e/app/src/main/res/mipmap-xhdpi/ic_skip_next_circle_black_24dp.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_skip_previous_circle_black_24dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GensaGames/Sample-LinkedListView/22e3de0d6411c4d030ba148b60658e72d559e09e/app/src/main/res/mipmap-xhdpi/ic_skip_previous_circle_black_24dp.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_star_black_24dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GensaGames/Sample-LinkedListView/22e3de0d6411c4d030ba148b60658e72d559e09e/app/src/main/res/mipmap-xhdpi/ic_star_black_24dp.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GensaGames/Sample-LinkedListView/22e3de0d6411c4d030ba148b60658e72d559e09e/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_pause_circle_black_24dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GensaGames/Sample-LinkedListView/22e3de0d6411c4d030ba148b60658e72d559e09e/app/src/main/res/mipmap-xxhdpi/ic_pause_circle_black_24dp.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_play_circle_filled_black_24dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GensaGames/Sample-LinkedListView/22e3de0d6411c4d030ba148b60658e72d559e09e/app/src/main/res/mipmap-xxhdpi/ic_play_circle_filled_black_24dp.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_skip_next_circle_black_24dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GensaGames/Sample-LinkedListView/22e3de0d6411c4d030ba148b60658e72d559e09e/app/src/main/res/mipmap-xxhdpi/ic_skip_next_circle_black_24dp.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_skip_previous_circle_black_24dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GensaGames/Sample-LinkedListView/22e3de0d6411c4d030ba148b60658e72d559e09e/app/src/main/res/mipmap-xxhdpi/ic_skip_previous_circle_black_24dp.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_star_black_24dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GensaGames/Sample-LinkedListView/22e3de0d6411c4d030ba148b60658e72d559e09e/app/src/main/res/mipmap-xxhdpi/ic_star_black_24dp.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GensaGames/Sample-LinkedListView/22e3de0d6411c4d030ba148b60658e72d559e09e/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_pause_circle_black_24dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GensaGames/Sample-LinkedListView/22e3de0d6411c4d030ba148b60658e72d559e09e/app/src/main/res/mipmap-xxxhdpi/ic_pause_circle_black_24dp.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_play_circle_filled_black_24dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GensaGames/Sample-LinkedListView/22e3de0d6411c4d030ba148b60658e72d559e09e/app/src/main/res/mipmap-xxxhdpi/ic_play_circle_filled_black_24dp.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_skip_next_circle_black_24dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GensaGames/Sample-LinkedListView/22e3de0d6411c4d030ba148b60658e72d559e09e/app/src/main/res/mipmap-xxxhdpi/ic_skip_next_circle_black_24dp.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_skip_previous_circle_black_24dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GensaGames/Sample-LinkedListView/22e3de0d6411c4d030ba148b60658e72d559e09e/app/src/main/res/mipmap-xxxhdpi/ic_skip_previous_circle_black_24dp.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_star_black_24dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GensaGames/Sample-LinkedListView/22e3de0d6411c4d030ba148b60658e72d559e09e/app/src/main/res/mipmap-xxxhdpi/ic_star_black_24dp.png -------------------------------------------------------------------------------- /app/src/main/res/raw/sample_song_1.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GensaGames/Sample-LinkedListView/22e3de0d6411c4d030ba148b60658e72d559e09e/app/src/main/res/raw/sample_song_1.mp3 -------------------------------------------------------------------------------- /app/src/main/res/values-v21/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/values-w820dp/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 64dp 6 | 7 | -------------------------------------------------------------------------------- /app/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #3F51B5 4 | #303F9F 5 | #FF4081 6 | 7 | #f27ea6 8 | 9 | -------------------------------------------------------------------------------- /app/src/main/res/values/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 16dp 4 | 16dp 5 | 180dp 6 | 16dp 7 | 8 | 9 | 150dp 10 | 100dp 11 | 120dp 12 | 42dp 13 | 30dp 14 | 5dp 15 | 170dp 16 | 50dp 17 | 18 | 19 | 20dp 20 | 10dp 21 | 22 | 23 | 130dp 24 | 100dp 25 | 6dp 26 | 10dp 27 | 28 | 29 | 360dp 30 | 70dp 31 | 340dp 32 | 50dp 33 | 34 | 6dp 35 | 6dp 36 | 6dp 37 | 35dp 38 | 14sp 39 | 12sp 40 | 41 | 42 | 40dp 43 | 80dp 44 | 45 | 46 | 47 | 34sp 48 | 49 | -------------------------------------------------------------------------------- /app/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | LinkedListView 3 | Settings 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 10 | 11 | 15 | 16 |