diff --git a/frontend/Movie_Pigeon/app/build.gradle b/frontend/Movie_Pigeon/app/build.gradle index ebbaba5..140b711 100644 --- a/frontend/Movie_Pigeon/app/build.gradle +++ b/frontend/Movie_Pigeon/app/build.gradle @@ -31,9 +31,6 @@ android { dependencies { compile fileTree(include: ['*.jar'], dir: 'libs') - androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', { - exclude group: 'com.android.support', module: 'support-annotations' - }) compile files('libs/universal-image-loader-1.9.5.jar') compile files('libs/gson-2.8.0.jar') compile files('libs/eventbus-3.0.0.jar') @@ -46,5 +43,15 @@ dependencies { compile 'com.google.code.gson:gson:2.8.0' compile 'org.greenrobot:eventbus:3.0.0' testCompile 'junit:junit:4.12' - androidTestCompile 'com.android.support.test.espresso:espresso-core:2.2.2' + androidTestCompile 'com.android.support:support-annotations:25.1.1' + + // Android runner and rules support + androidTestCompile 'com.android.support.test:runner:0.5' + androidTestCompile 'com.android.support.test:rules:0.5' + // Espresso support + androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', { + exclude group: 'com.android.support', module: 'support-annotations' + }) + // intent mocking support + androidTestCompile 'com.android.support.test.espresso:espresso-intents:2.2.2' } diff --git a/frontend/Movie_Pigeon/app/src/androidTest/java/org/example/team_pigeon/movie_pigeon/DisplayActivityTest.java b/frontend/Movie_Pigeon/app/src/androidTest/java/org/example/team_pigeon/movie_pigeon/DisplayActivityTest.java new file mode 100644 index 0000000..055819f --- /dev/null +++ b/frontend/Movie_Pigeon/app/src/androidTest/java/org/example/team_pigeon/movie_pigeon/DisplayActivityTest.java @@ -0,0 +1,57 @@ +package org.example.team_pigeon.movie_pigeon; + +import android.content.Context; +import android.content.Intent; +import android.os.Bundle; +import android.support.test.InstrumentationRegistry; +import android.support.test.rule.ActivityTestRule; +import android.support.test.runner.AndroidJUnit4; + +import org.example.team_pigeon.movie_pigeon.models.Movie; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; + +import java.util.ArrayList; + +import static android.support.test.espresso.Espresso.onData; +import static android.support.test.espresso.Espresso.onView; +import static android.support.test.espresso.assertion.ViewAssertions.matches; +import static android.support.test.espresso.matcher.ViewMatchers.isDisplayed; +import static android.support.test.espresso.matcher.ViewMatchers.withId; +import static android.support.test.espresso.matcher.ViewMatchers.withText; + +/** + * Created by SHENGX on 2017/3/19. + */ +@RunWith(AndroidJUnit4.class) +public class DisplayActivityTest { + @Rule + public ActivityTestRule displayActivityActivityTestRule = new ActivityTestRule(DisplayActivity.class) { + @Override + protected Intent getActivityIntent() { + ArrayList testMovieList = new ArrayList<>(); + for (int i = 0; i < 10; i++) { + testMovieList.add(new Movie(String.valueOf(i), "id")); + } + Bundle argument = new Bundle(); + argument.putSerializable("movieList", testMovieList); + argument.putString("title", "TestBar"); + argument.putString("type", "test"); + Context targetContext = InstrumentationRegistry.getInstrumentation().getTargetContext(); + Intent result = new Intent(targetContext, DisplayActivity.class); + result.putExtra("bundle",argument); + return result; + } + }; + + @Test + public void showMovieListProperly() { + onView(withId(R.id.toolbar_display_page)).check(matches(isDisplayed())); + onView(withId(R.id.list_movies)).check(matches(isDisplayed())); + for(int i = 0;i<10;i++) { + onData(withText(String.valueOf(i))).inAdapterView(withId(R.id.list_movies)).atPosition(i); + } + } + +} diff --git a/frontend/Movie_Pigeon/app/src/androidTest/java/org/example/team_pigeon/movie_pigeon/HomePageActivityTest.java b/frontend/Movie_Pigeon/app/src/androidTest/java/org/example/team_pigeon/movie_pigeon/HomePageActivityTest.java new file mode 100644 index 0000000..8b2d9b2 --- /dev/null +++ b/frontend/Movie_Pigeon/app/src/androidTest/java/org/example/team_pigeon/movie_pigeon/HomePageActivityTest.java @@ -0,0 +1,67 @@ +package org.example.team_pigeon.movie_pigeon; + +import android.content.Context; +import android.content.Intent; +import android.support.test.InstrumentationRegistry; +import android.support.test.rule.ActivityTestRule; +import android.support.test.runner.AndroidJUnit4; + +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; + +import static android.support.test.espresso.Espresso.onView; +import static android.support.test.espresso.action.ViewActions.click; +import static android.support.test.espresso.assertion.ViewAssertions.matches; +import static android.support.test.espresso.matcher.ViewMatchers.isDisplayed; +import static android.support.test.espresso.matcher.ViewMatchers.withId; +import static android.support.test.espresso.matcher.ViewMatchers.withText; + +/** + * Created by SHENGX on 2017/3/19. + */ + +@RunWith(AndroidJUnit4.class) +public class HomePageActivityTest { + @Rule + public ActivityTestRule homePageActivityActivityTestRule = new ActivityTestRule(HomePageActivity.class) { + @Override + protected Intent getActivityIntent() { + Context targetContext = InstrumentationRegistry.getInstrumentation().getTargetContext(); + Intent result = new Intent(targetContext, HomePageActivity.class); + result.putExtra("Token", "test token"); + return result; + } + }; + + @Test + public void ensureUiComponentsDisplayed() { + onView(withId(R.id.rg_tab_bar)) + .check(matches(isDisplayed())); + onView(withId(R.id.rb_now_showing)) + .check(matches(isDisplayed())); + onView(withId(R.id.rb_home)) + .check(matches(isDisplayed())); + onView(withId(R.id.rb_me)) + .check(matches(isDisplayed())); + onView(withId(R.id.view_pager)) + .check(matches(isDisplayed())); + onView(withId(R.id.rg_tab_bar)) + .check(matches(isDisplayed())); + } + + @Test + public void viewPagerSwitchCorrectly() { + onView(withText("Cinemas")).perform(click()); + onView(withId(R.id.spinner_cinema_brand)).check(matches(isDisplayed())); + onView(withText("Me")).perform(click()); + onView(withText("My Ratings")).check(matches(isDisplayed())); + onView(withText("My Bookmarks")).check(matches(isDisplayed())); + onView(withText("Settings")).check(matches(isDisplayed())); + onView(withText("Logout")).check(matches(isDisplayed())); + onView(withText("Home")).perform(click()); + onView(withId(R.id.search_view)).check(matches(isDisplayed())); + onView(withId(R.id.grid_now_showing)).check(matches(isDisplayed())); + onView(withId(R.id.grid_recommended)).check(matches(isDisplayed())); + } +} diff --git a/frontend/Movie_Pigeon/app/src/main/java/org/example/team_pigeon/movie_pigeon/CinemaFragment.java b/frontend/Movie_Pigeon/app/src/main/java/org/example/team_pigeon/movie_pigeon/CinemaFragment.java index 52dc730..f96aa83 100644 --- a/frontend/Movie_Pigeon/app/src/main/java/org/example/team_pigeon/movie_pigeon/CinemaFragment.java +++ b/frontend/Movie_Pigeon/app/src/main/java/org/example/team_pigeon/movie_pigeon/CinemaFragment.java @@ -25,6 +25,7 @@ import org.example.team_pigeon.movie_pigeon.models.Cinema; import org.example.team_pigeon.movie_pigeon.models.Movie; import org.example.team_pigeon.movie_pigeon.models.Schedule; +import org.example.team_pigeon.movie_pigeon.utils.TimeUtil; import org.greenrobot.eventbus.EventBus; import org.greenrobot.eventbus.Subscribe; @@ -71,6 +72,7 @@ public class CinemaFragment extends Fragment implements AdapterView.OnItemSelect private NowShowingListAdapter nowShowingListAdapter = null; private boolean isCinemasLoaded = false; private int currentDay; + private TimeUtil timeUtil = new TimeUtil(); public CinemaFragment() { @@ -82,8 +84,8 @@ public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View view = inflater.inflate(R.layout.fragment_cinema, container, false); bindViews(view); - dateList = getDateList(); - dateListInString = getDateListToString(dateList); + dateList = timeUtil.getDateList(); + dateListInString = timeUtil.getDateListToString_MMDDE(dateList); brands = this.getActivity().getResources().getStringArray(R.array.cinemaBrands); brandAdapter = new ArrayAdapter<>(this.getActivity(), R.layout.spinner_list_item,brands); brandSpinner.setAdapter(brandAdapter); @@ -151,27 +153,6 @@ private ArrayList convertToShowTimeArray(Date date, ArrayList return showTimeList; } - private List getDateList(){ - List week = new ArrayList<>(); - Calendar timeToAdd = Calendar.getInstance(); - Date date; - for(int i=0;i<7;i++){ - date = timeToAdd.getTime(); - week.add(date); - timeToAdd.add(Calendar.DATE,1); - } - return week; - } - - private List getDateListToString(List week){ - List stringList = new ArrayList<>(); - stringList.add("Please Choose Date"); - for(Date date:week){ - stringList.add(new SimpleDateFormat("MM-dd E", Locale.ENGLISH).format(date)); - } - return stringList; - } - @Override public void onItemSelected(AdapterView parent, View view, int position, long id) { String cinemaId; diff --git a/frontend/Movie_Pigeon/app/src/main/java/org/example/team_pigeon/movie_pigeon/DisplayActivity.java b/frontend/Movie_Pigeon/app/src/main/java/org/example/team_pigeon/movie_pigeon/DisplayActivity.java index e960abb..956b3fe 100644 --- a/frontend/Movie_Pigeon/app/src/main/java/org/example/team_pigeon/movie_pigeon/DisplayActivity.java +++ b/frontend/Movie_Pigeon/app/src/main/java/org/example/team_pigeon/movie_pigeon/DisplayActivity.java @@ -10,6 +10,15 @@ import android.view.MenuItem; import android.widget.FrameLayout; +import com.nostra13.universalimageloader.cache.disc.impl.UnlimitedDiskCache; +import com.nostra13.universalimageloader.cache.memory.impl.LruMemoryCache; +import com.nostra13.universalimageloader.core.ImageLoader; +import com.nostra13.universalimageloader.core.ImageLoaderConfiguration; +import com.nostra13.universalimageloader.core.assist.QueueProcessingType; +import com.nostra13.universalimageloader.utils.StorageUtils; + +import java.io.File; + public class DisplayActivity extends AppCompatActivity { private FrameLayout frameLayout; private android.app.FragmentManager fragmentManager = null; @@ -28,6 +37,9 @@ protected void onCreate(Bundle savedInstanceState) { setSupportActionBar(toolbar); fragmentManager = getFragmentManager(); frameLayout = (FrameLayout) findViewById(R.id.fl_content); + if(!ImageLoader.getInstance().isInited()){ + initImageLoaderConfig(); + } // add back arrow to toolbar if (getSupportActionBar() != null){ getSupportActionBar().setDisplayHomeAsUpEnabled(true); @@ -79,4 +91,19 @@ public boolean onOptionsItemSelected(MenuItem item) { return false; } + private void initImageLoaderConfig(){ + File cacheDir = StorageUtils.getOwnCacheDirectory(getApplicationContext(), "MoviePigeon/cache/poster"); + ImageLoaderConfiguration config = new ImageLoaderConfiguration.Builder(this) + .threadPoolSize(5) + .memoryCache(new LruMemoryCache(2 * 1024 * 1024)) + .memoryCacheSize(5 * 1024 * 1024) + .tasksProcessingOrder(QueueProcessingType.LIFO) + .diskCacheSize(50 * 1024 * 1024) + .diskCacheFileCount(200) + .diskCache(new UnlimitedDiskCache(cacheDir)) + .writeDebugLogs() + .build(); + ImageLoader.getInstance().init(config); + } + } diff --git a/frontend/Movie_Pigeon/app/src/main/java/org/example/team_pigeon/movie_pigeon/MeFragment.java b/frontend/Movie_Pigeon/app/src/main/java/org/example/team_pigeon/movie_pigeon/MeFragment.java index 31bdb50..2bf7b16 100644 --- a/frontend/Movie_Pigeon/app/src/main/java/org/example/team_pigeon/movie_pigeon/MeFragment.java +++ b/frontend/Movie_Pigeon/app/src/main/java/org/example/team_pigeon/movie_pigeon/MeFragment.java @@ -40,6 +40,7 @@ public class MeFragment extends Fragment { private View view; private Toolbar tbMe; private UserInfoSingleton userInfoBulk = UserInfoSingleton.getInstance(); + private LoadingDialog loadingDialog; private GlobalReceiver globalReceiver; private final int changeUsername = 0; @@ -50,6 +51,7 @@ public MeFragment() { public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { userInfoBulk.reset(); + loadingDialog = new LoadingDialog(this.getActivity(),R.style.LoadingDialog); view = inflater.inflate(R.layout.fragment_me, container, false); bindViews(view); myRatingsRow.setOnClickListener(new View.OnClickListener() { @@ -172,11 +174,13 @@ protected Integer doInBackground(String... params) { @Override protected void onPreExecute() { Log.i(TAG, "New search request is initialised"); + loadingDialog.show(); return; } @Override protected void onPostExecute(Integer status) { + loadingDialog.dismiss(); Intent displayActivityIntent = new Intent(getActivity(), DisplayActivity.class); Bundle arguments = new Bundle(); switch (status) { diff --git a/frontend/Movie_Pigeon/app/src/main/java/org/example/team_pigeon/movie_pigeon/MovieListFragment.java b/frontend/Movie_Pigeon/app/src/main/java/org/example/team_pigeon/movie_pigeon/MovieListFragment.java index 1e4766b..0997ce2 100644 --- a/frontend/Movie_Pigeon/app/src/main/java/org/example/team_pigeon/movie_pigeon/MovieListFragment.java +++ b/frontend/Movie_Pigeon/app/src/main/java/org/example/team_pigeon/movie_pigeon/MovieListFragment.java @@ -44,14 +44,7 @@ public class MovieListFragment extends Fragment implements AdapterView.OnItemCli private ArrayList movies; private ListView list_movies; private MovieListAdapter movieListAdapter; - private RequestHttpBuilderSingleton searchRequestHttpBuilder; - private Gson gson = new Gson(); public View footerView; - public boolean isLoading = false; - public boolean noMoreResult = false; - private ArrayList searchMovieList; - private MovieWithCount movieListWithCount; - private int resultCount; private Toolbar toolbar; private Bundle bundle; private String type; diff --git a/frontend/Movie_Pigeon/app/src/main/java/org/example/team_pigeon/movie_pigeon/MoviePageFragment.java b/frontend/Movie_Pigeon/app/src/main/java/org/example/team_pigeon/movie_pigeon/MoviePageFragment.java index 48a0306..c70746a 100644 --- a/frontend/Movie_Pigeon/app/src/main/java/org/example/team_pigeon/movie_pigeon/MoviePageFragment.java +++ b/frontend/Movie_Pigeon/app/src/main/java/org/example/team_pigeon/movie_pigeon/MoviePageFragment.java @@ -1,8 +1,10 @@ package org.example.team_pigeon.movie_pigeon; import android.app.Fragment; +import android.app.FragmentTransaction; import android.os.AsyncTask; import android.os.Bundle; +import android.support.v4.app.FragmentManager; import android.util.Log; import android.view.LayoutInflater; import android.view.Menu; @@ -10,6 +12,7 @@ import android.view.MenuItem; import android.view.View; import android.view.ViewGroup; +import android.widget.Button; import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.RatingBar; @@ -18,6 +21,8 @@ import android.widget.Toast; +import com.google.gson.Gson; +import com.google.gson.reflect.TypeToken; import com.nostra13.universalimageloader.core.DisplayImageOptions; import com.nostra13.universalimageloader.core.ImageLoader; @@ -27,6 +32,7 @@ import org.example.team_pigeon.movie_pigeon.eventCenter.UpdateMovieListEvent; import org.example.team_pigeon.movie_pigeon.models.Movie; import org.example.team_pigeon.movie_pigeon.models.PublicRating; +import org.example.team_pigeon.movie_pigeon.models.Schedule; import org.example.team_pigeon.movie_pigeon.models.UserBookmark; import org.example.team_pigeon.movie_pigeon.models.UserRating; import org.greenrobot.eventbus.EventBus; @@ -50,6 +56,7 @@ public class MoviePageFragment extends Fragment { private static final String UNBOOKMARK = "unbookmark"; private TextView txt_country, txt_length, txt_director, txt_plot, txt_genres, txt_year, txt_actors, score_imdb, score_douban, score_trakt, text_score; private TableRow row_country, row_length, row_director, row_genres, row_year, row_actors; + private Button btn_showtimes; private LinearLayout linearLayout_ratings; private ImageView image_poster, image_imdb, image_douban, image_trakt; private Movie movie; @@ -94,10 +101,12 @@ public boolean onOptionsItemSelected(MenuItem item) { case R.id.action_bookmark: if(isBookmarked){ + item.setEnabled(false); MyTask bookmarkTask = new MyTask(); bookmarkTask.execute(UNBOOKMARK, movie.getMovieID()); } else{ + item.setEnabled(false); userBookmark = new UserBookmark(movie.getMovieID()); MyTask bookmarkTask = new MyTask(); bookmarkTask.execute(BOOKMARK, movie.getMovieID()); @@ -132,6 +141,7 @@ private void loadViews(View view) { row_actors = (TableRow) view.findViewById(R.id.row_actors); linearLayout_ratings = (LinearLayout) view.findViewById(R.id.linear_ratings); ratingBar = (RatingBar) view.findViewById(R.id.ratingBar); + btn_showtimes = (Button) view.findViewById(R.id.btn_view_schedule); } private void setContent(Bundle argument) { @@ -177,11 +187,33 @@ private void setContent(Bundle argument) { public void onRatingChanged(RatingBar ratingBar, float rating, boolean fromUser) { if(fromUser){ userRating = new UserRating(movie.getMovieID(), String.valueOf(rating * 2)); + ratingBar.setEnabled(false); MyTask ratingTask = new MyTask(); ratingTask.execute(POST_RATING, movie.getMovieID(), String.valueOf(rating * 2)); } } }); + + //Set Schedule Button + if(!movie.isShowing()){ + btn_showtimes.setVisibility(View.GONE); + } + else { + btn_showtimes.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + android.app.FragmentManager fragmentManager = getFragmentManager(); + FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction(); + Bundle bundle = new Bundle(); + bundle.putSerializable("movie", movie); + MovieScheduleFragment movieScheduleFragment = new MovieScheduleFragment(); + movieScheduleFragment.setArguments(bundle); + fragmentTransaction.replace(R.id.fl_content, movieScheduleFragment); + fragmentTransaction.addToBackStack(movieScheduleFragment.getClass().getName()); + fragmentTransaction.commit(); + } + }); + } } } @@ -210,6 +242,7 @@ private void setRatingsOtherwiseSetGone(String rating, TextView score, ImageView } private void setBookmarkIcon(boolean isBookmarked){ + bookmarkItem.setEnabled(true); if(isBookmarked){ bookmarkItem.setIcon(R.drawable.ic_bookmark_full); } @@ -218,7 +251,7 @@ private void setBookmarkIcon(boolean isBookmarked){ } } - //Async thread to handle search request + //Async thread to handle http request private class MyTask extends AsyncTask { private int successfulStatus = -1; private final int SUCCESSFUL_UNBOOKMARK = 2; @@ -261,7 +294,7 @@ protected Integer doInBackground(String... params) { OkHttpClient client = requestHttpBuilder.getClient(); Response response = client.newCall(request).execute(); if (!response.isSuccessful()) { - Log.i(TAG, "rating failed" + response); + Log.i(TAG, "request" + requestType + "failed" + response); throw new IOException("Unexpected code" + response); } else { status = successfulStatus; @@ -285,6 +318,7 @@ protected void onPostExecute(Integer params) { case SUCCESSFUL_RATE: Log.i(TAG, "Rating is completed"); Toast.makeText(getActivity(), "Update rating successfully!", Toast.LENGTH_SHORT).show(); + ratingBar.setEnabled(true); movie.getUserRating().clear(); movie.getUserRating().add(userRating); EventBus.getDefault().post(new UpdateMovieListEvent(position, movie)); @@ -317,7 +351,6 @@ protected void onPostExecute(Integer params) { EventBus.getDefault().post(new UpdateMovieListEvent(position, movie)); } break; - case NO_INTERNET: Toast.makeText(getActivity(), "Connection error, please make sure that you have Internet connection.", Toast.LENGTH_SHORT).show(); break; diff --git a/frontend/Movie_Pigeon/app/src/main/java/org/example/team_pigeon/movie_pigeon/MovieScheduleFragment.java b/frontend/Movie_Pigeon/app/src/main/java/org/example/team_pigeon/movie_pigeon/MovieScheduleFragment.java new file mode 100644 index 0000000..18a8c4c --- /dev/null +++ b/frontend/Movie_Pigeon/app/src/main/java/org/example/team_pigeon/movie_pigeon/MovieScheduleFragment.java @@ -0,0 +1,271 @@ +package org.example.team_pigeon.movie_pigeon; + + +import android.app.Fragment; +import android.os.AsyncTask; +import android.os.Bundle; +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.ListView; +import android.widget.Spinner; +import android.widget.TextView; +import android.widget.Toast; + +import com.google.gson.Gson; +import com.google.gson.reflect.TypeToken; +import com.nostra13.universalimageloader.core.DisplayImageOptions; +import com.nostra13.universalimageloader.core.ImageLoader; + +import org.example.team_pigeon.movie_pigeon.adapters.ScheduleListAdapter; +import org.example.team_pigeon.movie_pigeon.configs.ImageConfig; +import org.example.team_pigeon.movie_pigeon.models.Movie; +import org.example.team_pigeon.movie_pigeon.models.Schedule; +import org.example.team_pigeon.movie_pigeon.utils.TimeUtil; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.Date; +import java.util.List; + +import okhttp3.OkHttpClient; +import okhttp3.Request; +import okhttp3.Response; + + +public class MovieScheduleFragment extends Fragment implements AdapterView.OnItemSelectedListener { + private static String TAG = "MovieScheduleFragment"; + private ListView scheduleListView; + private ImageView poster; + private TextView lengthText, genreText; + private Spinner dateSpinner; + private TimeUtil timeUtil = new TimeUtil(); + private List dateList; + private List dateListString; + private ArrayList rawSchedules; + private ArrayList> schedulesOfAWeek = new ArrayList<>(); + private ArrayList adapterList = new ArrayList<>(); + private Movie movie; + private ImageLoader imageLoader = ImageLoader.getInstance(); + private DisplayImageOptions options = new ImageConfig().getDisplayImageOption(); + private Boolean isDataReady = false; + private LoadingDialog loadingDialog; + + @Override + public void onCreate(Bundle savedInstanceState){ + super.onCreate(savedInstanceState); + Bundle bundle = getArguments(); + movie = (Movie)bundle.getSerializable("movie"); + dateList = timeUtil.getDateList(); + dateListString = timeUtil.getDateListToString_YYYYMMDD(dateList); + for (int i = 0; i < 7; i++) { + schedulesOfAWeek.add(new ArrayList()); + adapterList.add(new ScheduleListAdapter(schedulesOfAWeek.get(i), getActivity())); + } + } + + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { + loadingDialog = new LoadingDialog(this.getActivity(),R.style.LoadingDialog); + View view = inflater.inflate(R.layout.fragment_movie_schedule, container, false); + bindView(view); + + dateSpinner.setAdapter(new ArrayAdapter<>(getActivity(), R.layout.spinner_list_item, dateListString)); + dateSpinner.setOnItemSelectedListener(this); + //Set movie info views + setMovieInfoViews(); + + //Process raw schedules + GetScheduleTask task = new GetScheduleTask(); + task.execute(movie.getMovieID()); + + return view; + } + + //This method scan through the raw schedule data one by one, and add list item views where is needed. + //FYI, the raw date is sorted by date->cinema->movieType->time + private void prepareScheduleObjects() { + Boolean isValidDate = false; + int currentId = -1; + int currentDay = 0; + String currentDate = ""; + String currentType = ""; + Schedule currentSchedule = null; + ArrayList currentShowtimeArray = null; + + //Firstly, if the starting date of schedule is later than today, find it out. + int startingDay = -1; + for(int i=0;i=0){ + isValidDate = true; + currentSchedule = rawSchedules.get(0); + currentId = currentSchedule.getCinemaId(); + currentDate = currentSchedule.getDate(); + currentType = currentSchedule.getType(); + currentDay = startingDay; + currentSchedule.setShowTimeArray(new ArrayList()); + currentShowtimeArray = currentSchedule.getShowTimeArray(); + ScheduleListAdapter currentAdapter = adapterList.get(currentDay); + currentAdapter.addCinemaToAdapter(currentSchedule); + } + //Secondly, look at each schedule data, the logic is: + //1. find the starting position of with today's date, if the starting position is earlier than today. + //2. Compare each schedule with current date, cinemaId and type accordingly, if all are the same, then add its showtime into current schedule's showtime array. + //3. If any data is different, save the previous showtime array, and load this new schedule as current schedule. + //4. If the difference is date or cinemaId, meaning we need a new cinema title, add it to the adapter. + //5. If the date is different, increment currentDay, new data will be saved in a new adapter. Each day has a separated adapter to make the listView able to update. + for (int i = 0; i < rawSchedules.size() && currentDay < 7; ) { + if (isValidDate) { + if (rawSchedules.get(i).getDate().equals(currentDate)) { + if (rawSchedules.get(i).getCinemaId() == currentId) { + if (rawSchedules.get(i).getType().equals(currentType)) { + currentShowtimeArray.add(rawSchedules.get(i).getShowtime().substring(0, 5)); + i++; + //peek the next schedule, avoid index out of boundary + if (i == rawSchedules.size() || !rawSchedules.get(i).getType().equals(currentType) || rawSchedules.get(i).getCinemaId()!=currentId || !rawSchedules.get(i).getDate().equals(currentDate)) { + adapterList.get(currentDay).addScheduleItemToAdapter(currentSchedule); + } + } else { + currentSchedule = rawSchedules.get(i); + currentType = rawSchedules.get(i).getType(); + currentSchedule.setShowTimeArray(new ArrayList()); + currentShowtimeArray = currentSchedule.getShowTimeArray(); + } + } else { + currentSchedule = rawSchedules.get(i); + adapterList.get(currentDay).addCinemaToAdapter(currentSchedule); + currentId = currentSchedule.getCinemaId(); + currentType = currentSchedule.getType(); + currentSchedule.setShowTimeArray(new ArrayList()); + currentShowtimeArray = currentSchedule.getShowTimeArray(); + } + } else { + currentSchedule = rawSchedules.get(i); + currentDate = currentSchedule.getDate(); + currentDay++; + adapterList.get(currentDay).addCinemaToAdapter(currentSchedule); + currentId = currentSchedule.getCinemaId(); + currentType = currentSchedule.getType(); + currentSchedule.setShowTimeArray(new ArrayList()); + currentShowtimeArray = currentSchedule.getShowTimeArray(); + } + + } + //Find out the starting position, with today's date, ignore the outdated data + else { + if (rawSchedules.get(i).getDate().equals(dateListString.get(0))) { + currentSchedule = rawSchedules.get(i); + currentId = currentSchedule.getCinemaId(); + currentDate = currentSchedule.getDate(); + currentType = currentSchedule.getType(); + currentSchedule.setShowTimeArray(new ArrayList()); + currentShowtimeArray = currentSchedule.getShowTimeArray(); + ScheduleListAdapter currentAdapter = adapterList.get(currentDay); + currentAdapter.addCinemaToAdapter(currentSchedule); + isValidDate = true; + } else { + i++; + } + } + } + isDataReady = true; + } + + private void setMovieInfoViews() { + imageLoader.displayImage(movie.getPosterURL(), poster, options); + if (movie.getLength() != null) { + lengthText.setText(movie.getLength() + " Min"); + } + if (movie.getGenres() != null) { + genreText.setText(movie.getGenres()); + } + } + + private void bindView(View view) { + scheduleListView = (ListView) view.findViewById(R.id.list_schedules); + poster = (ImageView) view.findViewById(R.id.image_schedule_poster); + lengthText = (TextView) view.findViewById(R.id.text_schedule_length); + genreText = (TextView) view.findViewById(R.id.text_schedule_genre); + dateSpinner = (Spinner) view.findViewById(R.id.spinner_date_schedule); + } + + @Override + public void onItemSelected(AdapterView parent, View view, int position, long id) { + if (parent.getId() == R.id.spinner_date_schedule && isDataReady) { + scheduleListView.setAdapter(adapterList.get(position)); + adapterList.get(position).notifyDataSetChanged(); + if(adapterList.get(position).getCount()==0){ + Toast.makeText(getActivity(), "Sorry, there is no schedule available on this day.", Toast.LENGTH_SHORT).show(); + } + } + } + + @Override + public void onNothingSelected(AdapterView parent) { + + } + + //Async thread to handle search request + private class GetScheduleTask extends AsyncTask { + private final int SUCCESSFUL_SCHEDULE = 0; + private final int NO_INTERNET = 1; + private int status; + RequestHttpBuilderSingleton requestHttpBuilder = RequestHttpBuilderSingleton.getInstance(); + + @Override + protected Integer doInBackground(String... params) { + String movieId = params[0]; + + Request request = requestHttpBuilder.getScheduleOfMovie(movieId); + try { + OkHttpClient client = requestHttpBuilder.getClient(); + Response response = client.newCall(request).execute(); + if (!response.isSuccessful()) { + throw new IOException("Unexpected code" + response); + } else { + status = SUCCESSFUL_SCHEDULE; + Gson gson = new Gson(); + rawSchedules = gson.fromJson(response.body().charStream(), new TypeToken>() {}.getType()); + } + } catch (IOException e) { + Log.e(TAG, e.getMessage()); + return NO_INTERNET; + } + return null; + } + + @Override + protected void onPreExecute() { + Log.i(TAG, "Get schedule request is initialised"); + loadingDialog.show(); + return; + } + + @Override + protected void onPostExecute(Integer params) { + switch (status) { + case SUCCESSFUL_SCHEDULE: + Log.i(TAG, "Get Schedule succefully"); + prepareScheduleObjects(); + scheduleListView.setAdapter(adapterList.get(0)); + loadingDialog.dismiss(); + break; + + case NO_INTERNET: + Toast.makeText(getActivity(), "Connection error, please make sure that you have Internet connection.", Toast.LENGTH_SHORT).show(); + break; + } + + } + } +} diff --git a/frontend/Movie_Pigeon/app/src/main/java/org/example/team_pigeon/movie_pigeon/RecommendationFragment.java b/frontend/Movie_Pigeon/app/src/main/java/org/example/team_pigeon/movie_pigeon/RecommendationFragment.java index e15e069..971a116 100644 --- a/frontend/Movie_Pigeon/app/src/main/java/org/example/team_pigeon/movie_pigeon/RecommendationFragment.java +++ b/frontend/Movie_Pigeon/app/src/main/java/org/example/team_pigeon/movie_pigeon/RecommendationFragment.java @@ -81,7 +81,6 @@ public boolean onQueryTextChange(String newText) { @Override public void onItemClick(AdapterView parent, View view, int position, long id) { - Log.e(TAG,"tap"+String.valueOf(position)); Intent displayActivityIntent = new Intent(getActivity(), DisplayActivity.class); Bundle arguments = new Bundle(); switch (parent.getId()) { @@ -191,6 +190,9 @@ protected Void doInBackground(String... params) { } else{ status = SUCCESSFUL_NOW_SHOWING; + for(Movie movie:nowShowingMovieList){ + movie.setShowing(true); + } } return null; } @@ -270,7 +272,6 @@ protected void onPostExecute(Void params) { recommendedGrid.setAdapter(recommendedMovieAdapter); setOnclickListener(recommendedGrid); recommendedMovieAdapter.notifyDataSetChanged(); - Log.e(TAG,String.valueOf(recommendedMovieAdapter.getCount())); break; case ERROR: Toast.makeText(getActivity(), "Connection error, please check your connection", Toast.LENGTH_SHORT).show(); diff --git a/frontend/Movie_Pigeon/app/src/main/java/org/example/team_pigeon/movie_pigeon/RequestHttpBuilderSingleton.java b/frontend/Movie_Pigeon/app/src/main/java/org/example/team_pigeon/movie_pigeon/RequestHttpBuilderSingleton.java index d8d2719..4c295b5 100644 --- a/frontend/Movie_Pigeon/app/src/main/java/org/example/team_pigeon/movie_pigeon/RequestHttpBuilderSingleton.java +++ b/frontend/Movie_Pigeon/app/src/main/java/org/example/team_pigeon/movie_pigeon/RequestHttpBuilderSingleton.java @@ -22,9 +22,10 @@ public class RequestHttpBuilderSingleton { private final String bookmarkUrl = "http://128.199.167.57:8080/api/bookmarks"; private final String cinemaUrl = "http://128.199.167.57:8080/api/cinemas"; private final String nowShowingUrl = "http://128.199.167.57:8080/api/showing"; - //Same address as bookmark for testing + //Use bookmarks as place holders private final String recommendationUrl = "http://128.199.167.57:8080/api/bookmarks"; private final String nowShowingHomePageUrl = "http://128.199.167.57:8080/api/showing/all"; + private final String movieScheduleUrl = "http://128.199.167.57:8080/api/movies/schedule"; protected RequestHttpBuilderSingleton() {} @@ -99,6 +100,10 @@ public Request getShowingListRequest(String cinemaId){ return new Request.Builder().url(nowShowingUrl).header("Authorization", "Bearer "+ token.trim()).addHeader("cinema_id",cinemaId).build(); } + public Request getScheduleOfMovie(String movieId){ + return new Request.Builder().url(movieScheduleUrl).header("Authorization", "Bearer "+ token.trim()).addHeader("movie_id",movieId).build(); + } + public String getKeywords() { return keywords; } diff --git a/frontend/Movie_Pigeon/app/src/main/java/org/example/team_pigeon/movie_pigeon/SearchPageFragment.java b/frontend/Movie_Pigeon/app/src/main/java/org/example/team_pigeon/movie_pigeon/SearchPageFragment.java index 35e3113..89229a6 100644 --- a/frontend/Movie_Pigeon/app/src/main/java/org/example/team_pigeon/movie_pigeon/SearchPageFragment.java +++ b/frontend/Movie_Pigeon/app/src/main/java/org/example/team_pigeon/movie_pigeon/SearchPageFragment.java @@ -148,15 +148,6 @@ public void onDestroy() { EventBus.getDefault().unregister(this); } - @Override - public void onResume() { - super.onResume(); - } - - public void onPause() { - super.onPause(); - } - @Subscribe public void onEvent(UpdateMovieListEvent event) { if(movieListAdapter!=null) { diff --git a/frontend/Movie_Pigeon/app/src/main/java/org/example/team_pigeon/movie_pigeon/adapters/NowShowingListAdapter.java b/frontend/Movie_Pigeon/app/src/main/java/org/example/team_pigeon/movie_pigeon/adapters/NowShowingListAdapter.java index 9e34209..834b8a2 100644 --- a/frontend/Movie_Pigeon/app/src/main/java/org/example/team_pigeon/movie_pigeon/adapters/NowShowingListAdapter.java +++ b/frontend/Movie_Pigeon/app/src/main/java/org/example/team_pigeon/movie_pigeon/adapters/NowShowingListAdapter.java @@ -20,6 +20,7 @@ import org.example.team_pigeon.movie_pigeon.DisplayActivity; import org.example.team_pigeon.movie_pigeon.R; import org.example.team_pigeon.movie_pigeon.configs.ImageConfig; +import org.example.team_pigeon.movie_pigeon.costomizedViews.MultipleColGridView; import org.example.team_pigeon.movie_pigeon.models.Movie; import java.util.ArrayList; @@ -88,7 +89,7 @@ public View getView(final int position, View convertView, ViewGroup parent) { viewHolder.image_poster = (ImageView) convertView.findViewById(R.id.image_now_showing_list_poster); viewHolder.txt_length = (TextView) convertView.findViewById(R.id.text_now_showing_list_length); viewHolder.txt_special = (TextView) convertView.findViewById(R.id.text_now_showing_list_special); - viewHolder.grid_schedule = (GridView) convertView.findViewById(R.id.grid_schedule); + viewHolder.grid_schedule = (MultipleColGridView) convertView.findViewById(R.id.grid_schedule); viewHolder.ratingBar = (RatingBar) convertView.findViewById(R.id.ratingBar_now_showing); convertView.setTag(viewHolder); } else { @@ -136,7 +137,7 @@ private static class ViewHolder { TextView txt_length; TextView txt_special; ImageView image_poster; - GridView grid_schedule; + MultipleColGridView grid_schedule; RatingBar ratingBar; } } diff --git a/frontend/Movie_Pigeon/app/src/main/java/org/example/team_pigeon/movie_pigeon/adapters/ScheduleListAdapter.java b/frontend/Movie_Pigeon/app/src/main/java/org/example/team_pigeon/movie_pigeon/adapters/ScheduleListAdapter.java new file mode 100644 index 0000000..512f328 --- /dev/null +++ b/frontend/Movie_Pigeon/app/src/main/java/org/example/team_pigeon/movie_pigeon/adapters/ScheduleListAdapter.java @@ -0,0 +1,113 @@ +package org.example.team_pigeon.movie_pigeon.adapters; + +import android.content.Context; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ArrayAdapter; +import android.widget.BaseAdapter; +import android.widget.TextView; + + +import org.example.team_pigeon.movie_pigeon.R; +import org.example.team_pigeon.movie_pigeon.costomizedViews.MultipleColGridView; +import org.example.team_pigeon.movie_pigeon.models.Schedule; + +import java.util.ArrayList; +import java.util.TreeSet; + +public class ScheduleListAdapter extends BaseAdapter { + private static final int TYPE_SCHEDULE = 0; + private static final int TYPE_CINEMA = 1; + private ArrayList scheduleList; + private TreeSet cinemaSet = new TreeSet(); + private Context mContext; + private Schedule schedule; + + public ScheduleListAdapter(ArrayList scheduleList, Context mContext) { + this.mContext = mContext; + this.scheduleList = scheduleList; + } + + @Override + public int getItemViewType(int position) { + return cinemaSet.contains(position) ? TYPE_CINEMA : TYPE_SCHEDULE; + } + + @Override + public int getViewTypeCount() { + return 2; + } + + public void addCinemaToAdapter(final Schedule cinema) { + scheduleList.add(cinema); + cinemaSet.add(scheduleList.size() - 1); + this.notifyDataSetChanged(); + } + + + public void addScheduleItemToAdapter(Schedule schedule) { + scheduleList.add(schedule); + this.notifyDataSetChanged(); + } + + @Override + public int getCount() { + return scheduleList.size(); + } + + @Override + public Schedule getItem(int position) { + return scheduleList.get(position); + } + + @Override + public long getItemId(int position) { + return position; + } + + @Override + public View getView(int position, View convertView, ViewGroup parent) { + schedule = scheduleList.get(position); + ViewHolder viewHolder = null; + int type = getItemViewType(position); + if (convertView == null) { + viewHolder = new ViewHolder(); + switch (type) { + case TYPE_SCHEDULE: + convertView = LayoutInflater.from(mContext).inflate(R.layout.type_item_schedule, null); + viewHolder.txt_title = (TextView) convertView.findViewById(R.id.text_type_schedule); + viewHolder.grid = (MultipleColGridView) convertView.findViewById(R.id.grid_showtime_schedule); + break; + case TYPE_CINEMA: + convertView = LayoutInflater.from(mContext).inflate(R.layout.cinema_item_schedule, null); + viewHolder.txt_title = (TextView) convertView.findViewById(R.id.text_cinema_name); + break; + } + convertView.setClickable(false); + convertView.setTag(viewHolder); + } else { + viewHolder = (ViewHolder) convertView.getTag(); + } + switch (type) { + case TYPE_SCHEDULE: + if(!schedule.getType().equals("")) { + viewHolder.txt_title.setText(schedule.getType()); + } + else{ + viewHolder.txt_title.setText("2D"); + } + viewHolder.grid.setAdapter(new ArrayAdapter<>(this.mContext, R.layout.now_showing_schedule_cell, schedule.getShowTimeArray())); + break; + case TYPE_CINEMA: + viewHolder.txt_title.setText(schedule.getCinemaName()); + } + + return convertView; + } + + private static class ViewHolder { + TextView txt_title; + MultipleColGridView grid; + } +} diff --git a/frontend/Movie_Pigeon/app/src/main/java/org/example/team_pigeon/movie_pigeon/costomizedViews/MultipleColGridView.java b/frontend/Movie_Pigeon/app/src/main/java/org/example/team_pigeon/movie_pigeon/costomizedViews/MultipleColGridView.java new file mode 100644 index 0000000..558a516 --- /dev/null +++ b/frontend/Movie_Pigeon/app/src/main/java/org/example/team_pigeon/movie_pigeon/costomizedViews/MultipleColGridView.java @@ -0,0 +1,30 @@ +package org.example.team_pigeon.movie_pigeon.costomizedViews; + +import android.content.Context; +import android.util.AttributeSet; +import android.widget.GridView; + +/** + * Created by SHENGX on 2017/3/19. + */ + +public class MultipleColGridView extends GridView { + public MultipleColGridView(Context context, AttributeSet attrs) { + super(context, attrs); + } + + public MultipleColGridView(Context context) { + super(context); + } + + public MultipleColGridView(Context context, AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + } + + @Override + public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + int expandSpec = MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 2, MeasureSpec.AT_MOST); + super.onMeasure(widthMeasureSpec, expandSpec); + } +} + diff --git a/frontend/Movie_Pigeon/app/src/main/java/org/example/team_pigeon/movie_pigeon/models/Movie.java b/frontend/Movie_Pigeon/app/src/main/java/org/example/team_pigeon/movie_pigeon/models/Movie.java index f0b8082..bd9844c 100644 --- a/frontend/Movie_Pigeon/app/src/main/java/org/example/team_pigeon/movie_pigeon/models/Movie.java +++ b/frontend/Movie_Pigeon/app/src/main/java/org/example/team_pigeon/movie_pigeon/models/Movie.java @@ -58,6 +58,8 @@ public class Movie implements Serializable{ private boolean isRated; private boolean isReleased; private boolean isBookmarked; + @Expose + private boolean isShowing; public Movie(String title,String movieID){ this.title = title; @@ -231,4 +233,12 @@ public ArrayList getShowTimes() { public void setShowTimes(ArrayList showTimes) { this.showTimes = showTimes; } + + public boolean isShowing() { + return isShowing; + } + + public void setShowing(boolean showing) { + isShowing = showing; + } } diff --git a/frontend/Movie_Pigeon/app/src/main/java/org/example/team_pigeon/movie_pigeon/models/Schedule.java b/frontend/Movie_Pigeon/app/src/main/java/org/example/team_pigeon/movie_pigeon/models/Schedule.java index 5e8b56a..1385e75 100644 --- a/frontend/Movie_Pigeon/app/src/main/java/org/example/team_pigeon/movie_pigeon/models/Schedule.java +++ b/frontend/Movie_Pigeon/app/src/main/java/org/example/team_pigeon/movie_pigeon/models/Schedule.java @@ -4,6 +4,8 @@ import com.google.gson.annotations.SerializedName; import java.io.Serializable; +import java.lang.reflect.Array; +import java.util.ArrayList; /** * Created by SHENGX on 2017/3/4. @@ -14,12 +16,23 @@ public class Schedule implements Serializable{ private String movieId; @Expose @SerializedName("cinema_id") - private String cinemaId; + private int cinemaId; @Expose @SerializedName("schedule") private String time; @Expose + @SerializedName("time") + private String showtime; + @Expose private String type; + @Expose + @SerializedName("date") + private String date; + @Expose + @SerializedName("cinema_name") + private String cinemaName; + + private ArrayList showTimeArray; public String getMovieId() { return movieId; @@ -29,11 +42,11 @@ public void setMovieId(String movieId) { this.movieId = movieId; } - public String getCinemaId() { + public int getCinemaId() { return cinemaId; } - public void setCinemaId(String cinemaId) { + public void setCinemaId(int cinemaId) { this.cinemaId = cinemaId; } @@ -52,4 +65,36 @@ public String getType() { public void setType(String type) { this.type = type; } + + public String getDate() { + return date; + } + + public void setDate(String date) { + this.date = date; + } + + public String getCinemaName() { + return cinemaName; + } + + public void setCinemaName(String cinemaName) { + this.cinemaName = cinemaName; + } + + public ArrayList getShowTimeArray() { + return showTimeArray; + } + + public void setShowTimeArray(ArrayList showTimeArray) { + this.showTimeArray = showTimeArray; + } + + public String getShowtime() { + return showtime; + } + + public void setShowtime(String showtime) { + this.showtime = showtime; + } } diff --git a/frontend/Movie_Pigeon/app/src/main/java/org/example/team_pigeon/movie_pigeon/utils/TimeUtil.java b/frontend/Movie_Pigeon/app/src/main/java/org/example/team_pigeon/movie_pigeon/utils/TimeUtil.java new file mode 100644 index 0000000..7ff0a6f --- /dev/null +++ b/frontend/Movie_Pigeon/app/src/main/java/org/example/team_pigeon/movie_pigeon/utils/TimeUtil.java @@ -0,0 +1,45 @@ +package org.example.team_pigeon.movie_pigeon.utils; + +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.Calendar; +import java.util.Date; +import java.util.List; +import java.util.Locale; + +/** + * Created by SHENGX on 2017/3/18. + */ + +public class TimeUtil { + + public List getDateList(){ + List week = new ArrayList<>(); + Calendar timeToAdd = Calendar.getInstance(); + Date date; + for(int i=0;i<7;i++){ + date = timeToAdd.getTime(); + week.add(date); + timeToAdd.add(Calendar.DATE,1); + } + return week; + } + + //Used by cinema page + public List getDateListToString_MMDDE(List week){ + List stringList = new ArrayList<>(); + stringList.add("Please Choose Date"); + for(Date date:week){ + stringList.add(new SimpleDateFormat("MM-dd E", Locale.ENGLISH).format(date)); + } + return stringList; + } + + public List getDateListToString_YYYYMMDD(List week){ + List stringList = new ArrayList<>(); + for(Date date:week){ + stringList.add(new SimpleDateFormat("yyyy-MM-dd", Locale.ENGLISH).format(date)); + } + return stringList; + } +} diff --git a/frontend/Movie_Pigeon/app/src/main/res/layout/cinema_item_schedule.xml b/frontend/Movie_Pigeon/app/src/main/res/layout/cinema_item_schedule.xml new file mode 100644 index 0000000..e4461ff --- /dev/null +++ b/frontend/Movie_Pigeon/app/src/main/res/layout/cinema_item_schedule.xml @@ -0,0 +1,16 @@ + + + + + + \ No newline at end of file diff --git a/frontend/Movie_Pigeon/app/src/main/res/layout/fragment_me.xml b/frontend/Movie_Pigeon/app/src/main/res/layout/fragment_me.xml index c5ad641..fdfc650 100644 --- a/frontend/Movie_Pigeon/app/src/main/res/layout/fragment_me.xml +++ b/frontend/Movie_Pigeon/app/src/main/res/layout/fragment_me.xml @@ -33,7 +33,7 @@ diff --git a/frontend/Movie_Pigeon/app/src/main/res/layout/fragment_movie_page.xml b/frontend/Movie_Pigeon/app/src/main/res/layout/fragment_movie_page.xml index de48a2a..0215c2e 100644 --- a/frontend/Movie_Pigeon/app/src/main/res/layout/fragment_movie_page.xml +++ b/frontend/Movie_Pigeon/app/src/main/res/layout/fragment_movie_page.xml @@ -35,6 +35,16 @@ android:layout_height="222dp" android:adjustViewBounds="true" /> +