Java tutorial
/* * Copyright (C) 2016 SMedic * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.teocci.utubinbg.fragments; import android.accounts.AccountManager; import android.app.Activity; import android.content.Intent; import android.content.SharedPreferences; import android.os.Bundle; import android.os.Handler; import android.preference.PreferenceManager; import android.support.v4.app.Fragment; import android.support.v4.widget.SwipeRefreshLayout; import android.util.Log; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.AdapterView; import android.widget.ArrayAdapter; import android.widget.ImageView; import android.widget.TextView; import android.widget.Toast; import com.nhaarman.listviewanimations.appearance.simple.SwingBottomInAnimationAdapter; import com.nhaarman.listviewanimations.itemmanipulation.DynamicListView; import com.nhaarman.listviewanimations.util.Swappable; import com.teocci.utubinbg.BackgroundAudioService; import com.teocci.utubinbg.R; import com.teocci.utubinbg.YouTubePlaylist; import com.teocci.utubinbg.YouTubeSearch; import com.teocci.utubinbg.YouTubeVideo; import com.teocci.utubinbg.database.YouTubeSqlDb; import com.teocci.utubinbg.interfaces.YouTubePlaylistsReceiver; import com.teocci.utubinbg.interfaces.YouTubeVideosReceiver; import com.teocci.utubinbg.utils.Config; import com.teocci.utubinbg.utils.NetworkConf; import com.squareup.picasso.Picasso; import java.util.ArrayList; /** * Class that handles list of the playlists acquired from YouTube * Created by teocci on 7.3.16.. */ public class PlaylistsFragment extends Fragment implements YouTubeVideosReceiver, YouTubePlaylistsReceiver { private static final String TAG = "TEOCCI Playlists Fragmet"; private ArrayList<YouTubePlaylist> playlists; private DynamicListView playlistsListView; private Handler handler; private PlaylistAdapter playlistsAdapter; public static final String ACCOUNT_KEY = "accountName"; private String mChosenAccountName; private static final int REQUEST_ACCOUNT_PICKER = 2; private static final int REQUEST_AUTHORIZATION = 3; private YouTubeSearch youTubeSearch; private TextView userNameTextView; private NetworkConf networkConf; private SwipeRefreshLayout swipeToRefresh; public PlaylistsFragment() { // Required empty public constructor } @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); handler = new Handler(); playlists = new ArrayList<>(); youTubeSearch = new YouTubeSearch(getActivity(), this); youTubeSearch.setYouTubePlaylistsReceiver(this); youTubeSearch.setYouTubeVideosReceiver(this); networkConf = new NetworkConf(getActivity()); } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View v = inflater.inflate(R.layout.fragment_playlists, container, false); /* Setup the ListView */ playlistsListView = (DynamicListView) v.findViewById(R.id.playlists); userNameTextView = (TextView) v.findViewById(R.id.user_name); swipeToRefresh = (SwipeRefreshLayout) v.findViewById(R.id.swipeToRefresh); setupListViewAndAdapter(); if (savedInstanceState != null) { mChosenAccountName = savedInstanceState.getString(ACCOUNT_KEY); youTubeSearch.setAuthSelectedAccountName(mChosenAccountName); userNameTextView.setText(extractUserName(mChosenAccountName)); Toast.makeText(getContext(), "Hi " + extractUserName(mChosenAccountName), Toast.LENGTH_SHORT).show(); } else { loadAccount(); } return v; } /** * Loads account saved in preferences */ private void loadAccount() { SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(getActivity()); mChosenAccountName = sp.getString(ACCOUNT_KEY, null); if (mChosenAccountName != null) { youTubeSearch.setAuthSelectedAccountName(mChosenAccountName); userNameTextView.setText(extractUserName(mChosenAccountName)); Toast.makeText(getContext(), "Hi " + extractUserName(mChosenAccountName), Toast.LENGTH_SHORT).show(); } } /** * Save account in preferences for future usages */ private void saveAccount() { Log.d(TAG, "Saving account name... " + mChosenAccountName); SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(getActivity()); sp.edit().putString(ACCOUNT_KEY, mChosenAccountName).commit(); } @Override public void onResume() { super.onResume(); if (!getUserVisibleHint()) { //do nothing for now } playlists.clear(); playlists.addAll(YouTubeSqlDb.getInstance().playlists().readAll()); playlistsAdapter.notifyDataSetChanged(); } @Override public void setUserVisibleHint(boolean visible) { super.setUserVisibleHint(visible); if (visible && isResumed()) { //Log.d(TAG, "PlaylistsFragment visible and resumed"); //Only manually call onResume if fragment is already visible //Otherwise allow natural fragment lifecycle to call onResume onResume(); } } /** * Handles Google OAuth 2.0 authorization or account chosen result * * @param requestCode * @param resultCode * @param data */ @Override public void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); switch (requestCode) { case REQUEST_AUTHORIZATION: if (resultCode != Activity.RESULT_OK) { chooseAccount(); } break; case REQUEST_ACCOUNT_PICKER: if (resultCode == Activity.RESULT_OK && data != null && data.getExtras() != null) { String accountName = data.getExtras().getString(AccountManager.KEY_ACCOUNT_NAME); if (accountName != null) { mChosenAccountName = accountName; youTubeSearch.setAuthSelectedAccountName(accountName); userNameTextView.setText(extractUserName(mChosenAccountName)); Toast.makeText(getContext(), "Hi " + extractUserName(mChosenAccountName), Toast.LENGTH_SHORT) .show(); saveAccount(); } youTubeSearch.searchPlaylists(); } break; } } /** * Choose Google account if OAuth 2.0 choosing is necessary * acquiring YouTube private playlists requires OAuth 2.0 authorization */ private void chooseAccount() { startActivityForResult(youTubeSearch.getCredential().newChooseAccountIntent(), REQUEST_ACCOUNT_PICKER); } /** * Setups list view and adapter for storing YouTube playlists */ public void setupListViewAndAdapter() { playlistsAdapter = new PlaylistAdapter(getActivity()); SwingBottomInAnimationAdapter animationAdapter = new SwingBottomInAnimationAdapter(playlistsAdapter); animationAdapter.setAbsListView(playlistsListView); playlistsListView.setAdapter(animationAdapter); /* Enable drag and drop functionality */ playlistsListView.enableDragAndDrop(); playlistsListView.setOnItemLongClickListener(new AdapterView.OnItemLongClickListener() { @Override public boolean onItemLongClick(final AdapterView<?> parent, final View view, final int position, final long id) { playlistsListView.startDragging(position); return true; } }); swipeToRefresh.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() { @Override public void onRefresh() { if (networkConf.isNetworkAvailable()) { if (mChosenAccountName == null) { chooseAccount(); } else { youTubeSearch.searchPlaylists(); } } else { networkConf.createNetErrorDialog(); } } }); playlistsListView.setOnItemClickListener(new AdapterView.OnItemClickListener() { @Override public void onItemClick(AdapterView<?> av, View v, int pos, long id) { //check network connectivity if (!networkConf.isNetworkAvailable()) { networkConf.createNetErrorDialog(); return; } youTubeSearch.acquirePlaylistVideos(playlists.get(pos).getId()); //results are in onVideosReceived callback method } }); } /** * Called when playlist video items are received * * @param youTubeVideos - list to be played in background service */ @Override public void onVideosReceived(ArrayList<YouTubeVideo> youTubeVideos) { //if playlist is empty, do not start service if (youTubeVideos.isEmpty()) { getActivity().runOnUiThread(new Runnable() { public void run() { Toast.makeText(getContext(), "Playlist is empty!", Toast.LENGTH_SHORT).show(); } }); } else { Intent serviceIntent = new Intent(getContext(), BackgroundAudioService.class); serviceIntent.setAction(BackgroundAudioService.ACTION_PLAY); serviceIntent.putExtra(Config.YOUTUBE_TYPE, Config.YOUTUBE_MEDIA_TYPE_PLAYLIST); serviceIntent.putExtra(Config.YOUTUBE_TYPE_PLAYLIST, youTubeVideos); getActivity().startService(serviceIntent); } } @Override public void onPlaylistNotFound(final String playlistId, int errorCode) { Log.e(TAG, "Error 404. Playlist not found!"); getActivity().runOnUiThread(new Runnable() { public void run() { Toast.makeText(getContext(), "Playlist does not exist!", Toast.LENGTH_SHORT).show(); removePlaylist(playlistId); } }); } /** * Remove playlist with specific ID from DB and list * @param playlistId */ private void removePlaylist(final String playlistId) { YouTubeSqlDb.getInstance().playlists().delete(playlistId); for (YouTubePlaylist playlist : playlists) { if (playlist.getId().equals(playlistId)) { playlists.remove(playlist); break; } } playlistsAdapter.notifyDataSetChanged(); } /** * Called when playlists are received * * @param youTubePlaylists - list of playlists to be shown in list view */ @Override public void onPlaylistsReceived(ArrayList<YouTubePlaylist> youTubePlaylists) { //refresh playlists in database YouTubeSqlDb.getInstance().playlists().deleteAll(); for (YouTubePlaylist playlist : youTubePlaylists) { YouTubeSqlDb.getInstance().playlists().create(playlist); } playlists.clear(); playlists.addAll(youTubePlaylists); handler.post(new Runnable() { public void run() { if (playlistsAdapter != null) { playlistsAdapter.notifyDataSetChanged(); swipeToRefresh.setRefreshing(false); } } }); } /** * Extracts user name from email address * * @param emailAddress * @return */ private String extractUserName(String emailAddress) { String[] parts = emailAddress.split("@"); if (parts.length > 0 && parts[0] != null) return parts[0]; else return ""; } /** * Custom array adapter class which enables drag and drop list items swapping */ public class PlaylistAdapter extends ArrayAdapter<YouTubePlaylist> implements Swappable { public PlaylistAdapter(Activity context) { super(context, R.layout.video_item, playlists); } @Override public View getView(final int position, View convertView, ViewGroup parent) { if (convertView == null) { convertView = getActivity().getLayoutInflater().inflate(R.layout.playlist_item, parent, false); } ImageView thumbnail = (ImageView) convertView.findViewById(R.id.video_thumbnail); TextView title = (TextView) convertView.findViewById(R.id.playlist_title); TextView videosNumber = (TextView) convertView.findViewById(R.id.videos_number); TextView privacy = (TextView) convertView.findViewById(R.id.privacy); YouTubePlaylist searchResult = playlists.get(position); Picasso.with(getContext()).load(searchResult.getThumbnailURL()).into(thumbnail); title.setText(searchResult.getTitle()); videosNumber.setText("Number of videos: " + String.valueOf(searchResult.getNumberOfVideos())); privacy.setText("Status: " + searchResult.getStatus()); return convertView; } @Override public long getItemId(int i) { return getItem(i).hashCode(); } @Override public boolean hasStableIds() { return true; } @Override public void swapItems(int i, int i1) { YouTubePlaylist firstItem = getItem(i); playlists.set(i, getItem(i1)); playlists.set(i1, firstItem); notifyDataSetChanged(); } } }