@ -1,39 +0,0 @@ |
|||
image: openjdk:8-jdk |
|||
|
|||
variables: |
|||
ANDROID_TARGET_SDK: "26" |
|||
ANDROID_BUILD_TOOLS: "27.0.0" |
|||
ANDROID_SDK_TOOLS_REV: "3859397" |
|||
|
|||
before_script: |
|||
- apt-get --quiet update --yes |
|||
- apt-get --quiet install --yes wget unzip lib32stdc++6 lib32z1 |
|||
- mkdir $HOME/.android # for sdkmanager configs |
|||
- echo 'count=0' > $HOME/.android/repositories.cfg # avoid warning |
|||
- wget --quiet --output-document=android-sdk.zip https://dl.google.com/android/repository/sdk-tools-linux-${ANDROID_SDK_TOOLS_REV}.zip |
|||
- mkdir $PWD/android-sdk-linux |
|||
- unzip -qq android-sdk.zip -d $PWD/android-sdk-linux |
|||
- export ANDROID_HOME=$PWD/android-sdk-linux |
|||
- echo y | $ANDROID_HOME/tools/bin/sdkmanager --update > /dev/null |
|||
- echo y | $ANDROID_HOME/tools/bin/sdkmanager 'tools' > /dev/null |
|||
- echo y | $ANDROID_HOME/tools/bin/sdkmanager 'platform-tools' > /dev/null |
|||
- echo y | $ANDROID_HOME/tools/bin/sdkmanager 'build-tools;'$ANDROID_BUILD_TOOLS > /dev/null |
|||
- echo y | $ANDROID_HOME/tools/bin/sdkmanager 'platforms;android-'$ANDROID_TARGET_SDK > /dev/null |
|||
- echo y | $ANDROID_HOME/tools/bin/sdkmanager 'extras;android;m2repository' > /dev/null |
|||
- echo y | $ANDROID_HOME/tools/bin/sdkmanager 'extras;google;google_play_services' > /dev/null |
|||
- echo y | $ANDROID_HOME/tools/bin/sdkmanager 'extras;google;m2repository' > /dev/null |
|||
- chmod +x ./gradlew |
|||
|
|||
stages: |
|||
- build |
|||
|
|||
build: |
|||
stage: build |
|||
script: |
|||
- ./gradlew assembleDebug > /dev/null |
|||
except: |
|||
- master |
|||
artifacts: |
|||
name: "${CI_BUILD_NAME}" |
|||
paths: |
|||
- app/build/outputs/ |
@ -1,161 +0,0 @@ |
|||
package gr.thmmy.mthmmy.activities; |
|||
|
|||
import android.content.Intent; |
|||
import android.graphics.Typeface; |
|||
import android.os.Build; |
|||
import android.os.Bundle; |
|||
import android.view.LayoutInflater; |
|||
import android.view.View; |
|||
import android.widget.LinearLayout; |
|||
import android.widget.TextView; |
|||
|
|||
import gr.thmmy.mthmmy.R; |
|||
import gr.thmmy.mthmmy.activities.board.BoardActivity; |
|||
import gr.thmmy.mthmmy.activities.topic.TopicActivity; |
|||
import gr.thmmy.mthmmy.base.BaseActivity; |
|||
import gr.thmmy.mthmmy.model.Bookmark; |
|||
|
|||
import static gr.thmmy.mthmmy.activities.board.BoardActivity.BUNDLE_BOARD_TITLE; |
|||
import static gr.thmmy.mthmmy.activities.board.BoardActivity.BUNDLE_BOARD_URL; |
|||
import static gr.thmmy.mthmmy.activities.topic.TopicActivity.BUNDLE_TOPIC_TITLE; |
|||
import static gr.thmmy.mthmmy.activities.topic.TopicActivity.BUNDLE_TOPIC_URL; |
|||
|
|||
//TODO proper handling with adapter etc.
|
|||
//TODO better UI
|
|||
//TODO after clicking bookmark and then back button should return to this activity
|
|||
public class BookmarkActivity extends BaseActivity { |
|||
private TextView boardsTitle; |
|||
private TextView topicsTitle; |
|||
|
|||
@Override |
|||
protected void onCreate(Bundle savedInstanceState) { |
|||
super.onCreate(savedInstanceState); |
|||
setContentView(R.layout.activity_bookmark); |
|||
|
|||
//Initialize toolbar
|
|||
toolbar = findViewById(R.id.toolbar); |
|||
toolbar.setTitle("Bookmarks"); |
|||
setSupportActionBar(toolbar); |
|||
if (getSupportActionBar() != null) { |
|||
getSupportActionBar().setDisplayHomeAsUpEnabled(true); |
|||
getSupportActionBar().setDisplayShowHomeEnabled(true); |
|||
} |
|||
|
|||
createDrawer(); |
|||
drawer.setSelection(BOOKMARKS_ID); |
|||
|
|||
LinearLayout bookmarksLinearView = findViewById(R.id.bookmarks_container); |
|||
LayoutInflater layoutInflater = getLayoutInflater(); |
|||
|
|||
if(!getBoardsBookmarked().isEmpty()) { |
|||
boardsTitle = new TextView(this); |
|||
boardsTitle.setLayoutParams(new LinearLayout.LayoutParams( |
|||
LinearLayout.LayoutParams.MATCH_PARENT |
|||
, LinearLayout.LayoutParams.WRAP_CONTENT)); |
|||
boardsTitle.setText(getString(R.string.board_bookmarks_title)); |
|||
boardsTitle.setTypeface(boardsTitle.getTypeface(), Typeface.BOLD); |
|||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { |
|||
boardsTitle.setTextColor(getColor(R.color.primary_text)); |
|||
} else { |
|||
//noinspection deprecation
|
|||
boardsTitle.setTextColor(getResources().getColor(R.color.primary_text)); |
|||
} |
|||
boardsTitle.setTextAlignment(View.TEXT_ALIGNMENT_CENTER); |
|||
boardsTitle.setTextSize(20f); |
|||
bookmarksLinearView.addView(boardsTitle); |
|||
|
|||
for (final Bookmark bookmarkedBoard : getBoardsBookmarked()) { |
|||
if (bookmarkedBoard != null && bookmarkedBoard.getTitle() != null) { |
|||
final LinearLayout row = (LinearLayout) layoutInflater.inflate( |
|||
R.layout.activity_bookmark_row, bookmarksLinearView, false); |
|||
row.setOnClickListener(new View.OnClickListener() { |
|||
@Override |
|||
public void onClick(View view) { |
|||
Intent intent = new Intent(BookmarkActivity.this, BoardActivity.class); |
|||
Bundle extras = new Bundle(); |
|||
extras.putString(BUNDLE_BOARD_URL, "https://www.thmmy.gr/smf/index.php?board=" |
|||
+ bookmarkedBoard.getId() + ".0"); |
|||
extras.putString(BUNDLE_BOARD_TITLE, bookmarkedBoard.getTitle()); |
|||
intent.putExtras(extras); |
|||
startActivity(intent); |
|||
finish(); |
|||
} |
|||
}); |
|||
((TextView) row.findViewById(R.id.bookmark_title)).setText(bookmarkedBoard.getTitle()); |
|||
(row.findViewById(R.id.remove_bookmark)).setOnClickListener(new View.OnClickListener() { |
|||
@Override |
|||
public void onClick(View view) { |
|||
removeBookmark(bookmarkedBoard); |
|||
row.setVisibility(View.GONE); |
|||
updateTitles(); |
|||
} |
|||
}); |
|||
bookmarksLinearView.addView(row); |
|||
} |
|||
} |
|||
} |
|||
|
|||
|
|||
if(!getTopicsBookmarked().isEmpty()) { |
|||
topicsTitle = new TextView(this); |
|||
topicsTitle.setLayoutParams(new LinearLayout.LayoutParams( |
|||
LinearLayout.LayoutParams.MATCH_PARENT |
|||
, LinearLayout.LayoutParams.WRAP_CONTENT)); |
|||
topicsTitle.setText(getString(R.string.topic_bookmarks_title)); |
|||
topicsTitle.setTypeface(topicsTitle.getTypeface(), Typeface.BOLD); |
|||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { |
|||
topicsTitle.setTextColor(getColor(R.color.primary_text)); |
|||
} else { |
|||
//noinspection deprecation
|
|||
topicsTitle.setTextColor(getResources().getColor(R.color.primary_text)); |
|||
} |
|||
topicsTitle.setTextAlignment(View.TEXT_ALIGNMENT_CENTER); |
|||
topicsTitle.setTextSize(20f); |
|||
bookmarksLinearView.addView(topicsTitle); |
|||
|
|||
for (final Bookmark bookmarkedTopic : getTopicsBookmarked()) { |
|||
if (bookmarkedTopic != null && bookmarkedTopic.getTitle() != null) { |
|||
final LinearLayout row = (LinearLayout) layoutInflater.inflate( |
|||
R.layout.activity_bookmark_row, bookmarksLinearView, false); |
|||
row.setOnClickListener(new View.OnClickListener() { |
|||
@Override |
|||
public void onClick(View view) { |
|||
Intent intent = new Intent(BookmarkActivity.this, TopicActivity.class); |
|||
Bundle extras = new Bundle(); |
|||
extras.putString(BUNDLE_TOPIC_URL, "https://www.thmmy.gr/smf/index.php?topic=" |
|||
+ bookmarkedTopic.getId() + "." + 2147483647); |
|||
extras.putString(BUNDLE_TOPIC_TITLE, bookmarkedTopic.getTitle()); |
|||
intent.putExtras(extras); |
|||
startActivity(intent); |
|||
finish(); |
|||
} |
|||
}); |
|||
((TextView) row.findViewById(R.id.bookmark_title)).setText(bookmarkedTopic.getTitle()); |
|||
(row.findViewById(R.id.remove_bookmark)).setOnClickListener(new View.OnClickListener() { |
|||
@Override |
|||
public void onClick(View view) { |
|||
removeBookmark(bookmarkedTopic); |
|||
row.setVisibility(View.GONE); |
|||
updateTitles(); |
|||
} |
|||
}); |
|||
bookmarksLinearView.addView(row); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
|
|||
@Override |
|||
protected void onResume() { |
|||
drawer.setSelection(BOOKMARKS_ID); |
|||
super.onResume(); |
|||
} |
|||
|
|||
private void updateTitles() |
|||
{ |
|||
if(getBoardsBookmarked().isEmpty()&&boardsTitle!=null) |
|||
boardsTitle.setVisibility(View.GONE); |
|||
if(getTopicsBookmarked().isEmpty()&&topicsTitle!=null) |
|||
topicsTitle.setVisibility(View.GONE); |
|||
} |
|||
} |
@ -0,0 +1,130 @@ |
|||
package gr.thmmy.mthmmy.activities.bookmarks; |
|||
|
|||
import android.app.Activity; |
|||
import android.graphics.Typeface; |
|||
import android.os.Build; |
|||
import android.os.Bundle; |
|||
import android.support.annotation.NonNull; |
|||
import android.support.v4.app.Fragment; |
|||
import android.view.LayoutInflater; |
|||
import android.view.View; |
|||
import android.view.ViewGroup; |
|||
import android.widget.LinearLayout; |
|||
import android.widget.TextView; |
|||
|
|||
import java.util.ArrayList; |
|||
|
|||
import gr.thmmy.mthmmy.R; |
|||
import gr.thmmy.mthmmy.model.Bookmark; |
|||
|
|||
/** |
|||
* A {@link Fragment} subclass. |
|||
* Use the {@link BoardBookmarksFragment#newInstance} factory method to |
|||
* create an instance of this fragment. |
|||
*/ |
|||
public class BoardBookmarksFragment extends Fragment { |
|||
protected static final String ARG_SECTION_NUMBER = "SECTION_NUMBER"; |
|||
protected static final String ARG_BOARD_BOOKMARKS = "BOARD_BOOKMARKS"; |
|||
|
|||
public static final String INTERACTION_CLICK_BOARD_BOOKMARK = "CLICK_BOARD_BOOKMARK"; |
|||
public static final String INTERACTION_REMOVE_BOARD_BOOKMARK= "REMOVE_BOARD_BOOKMARK"; |
|||
|
|||
ArrayList<Bookmark> boardBookmarks = null; |
|||
|
|||
// Required empty public constructor
|
|||
public BoardBookmarksFragment() { |
|||
} |
|||
|
|||
/** |
|||
* Use ONLY this factory method to create a new instance of |
|||
* this fragment using the provided parameters. |
|||
* |
|||
* @return A new instance of fragment Forum. |
|||
*/ |
|||
public static BoardBookmarksFragment newInstance(int sectionNumber, String boardBookmarks) { |
|||
BoardBookmarksFragment fragment = new BoardBookmarksFragment(); |
|||
Bundle args = new Bundle(); |
|||
args.putInt(ARG_SECTION_NUMBER, sectionNumber); |
|||
args.putString(ARG_BOARD_BOOKMARKS, boardBookmarks); |
|||
fragment.setArguments(args); |
|||
return fragment; |
|||
} |
|||
|
|||
@Override |
|||
public void onCreate(Bundle savedInstanceState) { |
|||
super.onCreate(savedInstanceState); |
|||
if (getArguments() != null) { |
|||
String bundledBoardBookmarks = getArguments().getString(ARG_BOARD_BOOKMARKS); |
|||
if (bundledBoardBookmarks != null) { |
|||
boardBookmarks = Bookmark.arrayFromString(bundledBoardBookmarks); |
|||
} |
|||
} |
|||
} |
|||
|
|||
@Override |
|||
public View onCreateView(@NonNull LayoutInflater layoutInflater, ViewGroup container, |
|||
Bundle savedInstanceState) { |
|||
// Inflates the layout for this fragment
|
|||
final View rootView = layoutInflater.inflate(R.layout.fragment_bookmarks, container, false); |
|||
//bookmarks_board_container
|
|||
final LinearLayout bookmarksLinearView = rootView.findViewById(R.id.bookmarks_container); |
|||
|
|||
if(this.boardBookmarks != null && !this.boardBookmarks.isEmpty()) { |
|||
for (final Bookmark bookmarkedBoard : boardBookmarks) { |
|||
if (bookmarkedBoard != null && bookmarkedBoard.getTitle() != null) { |
|||
final LinearLayout row = (LinearLayout) layoutInflater.inflate( |
|||
R.layout.fragment_bookmarks_board_row, bookmarksLinearView, false); |
|||
row.setOnClickListener(new View.OnClickListener() { |
|||
@Override |
|||
public void onClick(View view) { |
|||
Activity activity = getActivity(); |
|||
if (activity instanceof BookmarkActivity){ |
|||
((BookmarkActivity) activity).onBoardInteractionListener(INTERACTION_CLICK_BOARD_BOOKMARK, bookmarkedBoard); |
|||
} |
|||
} |
|||
}); |
|||
((TextView) row.findViewById(R.id.bookmark_title)).setText(bookmarkedBoard.getTitle()); |
|||
(row.findViewById(R.id.remove_bookmark)).setOnClickListener(new View.OnClickListener() { |
|||
@Override |
|||
public void onClick(View view) { |
|||
Activity activity = getActivity(); |
|||
if (activity instanceof BookmarkActivity){ |
|||
((BookmarkActivity) activity).onBoardInteractionListener(INTERACTION_REMOVE_BOARD_BOOKMARK, bookmarkedBoard); |
|||
boardBookmarks.remove(bookmarkedBoard); |
|||
} |
|||
row.setVisibility(View.GONE); |
|||
|
|||
if (boardBookmarks.isEmpty()){ |
|||
bookmarksLinearView.addView(bookmarksListEmptyMessage()); |
|||
} |
|||
} |
|||
}); |
|||
bookmarksLinearView.addView(row); |
|||
} |
|||
} |
|||
} else { |
|||
|
|||
bookmarksLinearView.addView(bookmarksListEmptyMessage()); |
|||
} |
|||
|
|||
return rootView; |
|||
} |
|||
|
|||
private TextView bookmarksListEmptyMessage() { |
|||
TextView emptyBookmarksCategory = new TextView(this.getContext()); |
|||
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams( |
|||
LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT); |
|||
params.setMargins(0, 12, 0, 0); |
|||
emptyBookmarksCategory.setLayoutParams(params); |
|||
emptyBookmarksCategory.setText(getString(R.string.empty_board_bookmarks)); |
|||
emptyBookmarksCategory.setTypeface(emptyBookmarksCategory.getTypeface(), Typeface.BOLD); |
|||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { |
|||
emptyBookmarksCategory.setTextColor(this.getContext().getColor(R.color.primary_text)); |
|||
} else { |
|||
//noinspection deprecation
|
|||
emptyBookmarksCategory.setTextColor(this.getContext().getResources().getColor(R.color.primary_text)); |
|||
} |
|||
emptyBookmarksCategory.setTextAlignment(View.TEXT_ALIGNMENT_CENTER); |
|||
return emptyBookmarksCategory; |
|||
} |
|||
} |
@ -0,0 +1,143 @@ |
|||
package gr.thmmy.mthmmy.activities.bookmarks; |
|||
|
|||
import android.content.Intent; |
|||
import android.graphics.drawable.Drawable; |
|||
import android.os.Bundle; |
|||
import android.support.design.widget.TabLayout; |
|||
import android.support.v4.app.Fragment; |
|||
import android.support.v4.app.FragmentManager; |
|||
import android.support.v4.app.FragmentPagerAdapter; |
|||
import android.support.v4.view.ViewPager; |
|||
import android.widget.Toast; |
|||
|
|||
import java.util.ArrayList; |
|||
import java.util.List; |
|||
|
|||
import gr.thmmy.mthmmy.R; |
|||
import gr.thmmy.mthmmy.activities.board.BoardActivity; |
|||
import gr.thmmy.mthmmy.activities.topic.TopicActivity; |
|||
import gr.thmmy.mthmmy.base.BaseActivity; |
|||
import gr.thmmy.mthmmy.model.Bookmark; |
|||
|
|||
import static gr.thmmy.mthmmy.activities.board.BoardActivity.BUNDLE_BOARD_TITLE; |
|||
import static gr.thmmy.mthmmy.activities.board.BoardActivity.BUNDLE_BOARD_URL; |
|||
import static gr.thmmy.mthmmy.activities.topic.TopicActivity.BUNDLE_TOPIC_TITLE; |
|||
import static gr.thmmy.mthmmy.activities.topic.TopicActivity.BUNDLE_TOPIC_URL; |
|||
|
|||
//TODO proper handling with adapter etc.
|
|||
//TODO after clicking bookmark and then back button should return to this activity
|
|||
public class BookmarkActivity extends BaseActivity { |
|||
@Override |
|||
protected void onCreate(Bundle savedInstanceState) { |
|||
super.onCreate(savedInstanceState); |
|||
setContentView(R.layout.activity_bookmark); |
|||
|
|||
//Initialize toolbar
|
|||
toolbar = findViewById(R.id.toolbar); |
|||
toolbar.setTitle("Bookmarks"); |
|||
setSupportActionBar(toolbar); |
|||
if (getSupportActionBar() != null) { |
|||
getSupportActionBar().setDisplayHomeAsUpEnabled(true); |
|||
getSupportActionBar().setDisplayShowHomeEnabled(true); |
|||
} |
|||
|
|||
createDrawer(); |
|||
drawer.setSelection(BOOKMARKS_ID); |
|||
|
|||
//Creates the adapter that will return a fragment for each section of the activity
|
|||
SectionsPagerAdapter sectionsPagerAdapter = new SectionsPagerAdapter(getSupportFragmentManager()); |
|||
sectionsPagerAdapter.addFragment(TopicBookmarksFragment.newInstance(1, Bookmark.arrayToString(getTopicsBookmarked())), "Topics"); |
|||
sectionsPagerAdapter.addFragment(BoardBookmarksFragment.newInstance(2, Bookmark.arrayToString(getBoardsBookmarked())), "Boards"); |
|||
|
|||
//Sets up the ViewPager with the sections adapter.
|
|||
ViewPager viewPager = findViewById(R.id.bookmarks_container); |
|||
viewPager.setAdapter(sectionsPagerAdapter); |
|||
|
|||
TabLayout tabLayout = findViewById(R.id.bookmark_tabs); |
|||
tabLayout.setupWithViewPager(viewPager); |
|||
} |
|||
|
|||
@Override |
|||
protected void onResume() { |
|||
drawer.setSelection(BOOKMARKS_ID); |
|||
super.onResume(); |
|||
} |
|||
|
|||
public boolean onTopicInteractionListener(String interactionType, Bookmark bookmarkedTopic){ |
|||
if (interactionType.equals(TopicBookmarksFragment.INTERACTION_CLICK_TOPIC_BOOKMARK)){ |
|||
Intent intent = new Intent(BookmarkActivity.this, TopicActivity.class); |
|||
Bundle extras = new Bundle(); |
|||
extras.putString(BUNDLE_TOPIC_URL, "https://www.thmmy.gr/smf/index.php?topic=" |
|||
+ bookmarkedTopic.getId() + "." + 2147483647); |
|||
extras.putString(BUNDLE_TOPIC_TITLE, bookmarkedTopic.getTitle()); |
|||
intent.putExtras(extras); |
|||
startActivity(intent); |
|||
finish(); |
|||
} else if (interactionType.equals(TopicBookmarksFragment.INTERACTION_TOGGLE_TOPIC_NOTIFICATION)) { |
|||
return toggleNotification(bookmarkedTopic); |
|||
} else if (interactionType.equals(TopicBookmarksFragment.INTERACTION_REMOVE_TOPIC_BOOKMARK)){ |
|||
removeBookmark(bookmarkedTopic); |
|||
Toast.makeText(BookmarkActivity.this, "Bookmark removed", Toast.LENGTH_SHORT).show(); |
|||
} |
|||
return true; |
|||
} |
|||
|
|||
public void onBoardInteractionListener(String interactionType, Bookmark bookmarkedBoard){ |
|||
if (interactionType.equals(BoardBookmarksFragment.INTERACTION_CLICK_BOARD_BOOKMARK)){ |
|||
Intent intent = new Intent(BookmarkActivity.this, BoardActivity.class); |
|||
Bundle extras = new Bundle(); |
|||
extras.putString(BUNDLE_BOARD_URL, "https://www.thmmy.gr/smf/index.php?board=" |
|||
+ bookmarkedBoard.getId() + ".0"); |
|||
extras.putString(BUNDLE_BOARD_TITLE, bookmarkedBoard.getTitle()); |
|||
intent.putExtras(extras); |
|||
startActivity(intent); |
|||
finish(); |
|||
} else if (interactionType.equals(BoardBookmarksFragment.INTERACTION_REMOVE_BOARD_BOOKMARK)){ |
|||
removeBookmark(bookmarkedBoard); |
|||
Toast.makeText(BookmarkActivity.this, "Bookmark removed", Toast.LENGTH_SHORT).show(); |
|||
} |
|||
} |
|||
|
|||
/** |
|||
* A {@link FragmentPagerAdapter} that returns a fragment corresponding to |
|||
* one of the sections/tabs/pages. If it becomes too memory intensive, |
|||
* it may be best to switch to a |
|||
* {@link android.support.v4.app.FragmentStatePagerAdapter}. |
|||
*/ |
|||
private class SectionsPagerAdapter extends FragmentPagerAdapter { |
|||
private final List<Fragment> fragmentList = new ArrayList<>(); |
|||
private final List<String> fragmentTitleList = new ArrayList<>(); |
|||
|
|||
SectionsPagerAdapter(FragmentManager fm) { |
|||
super(fm); |
|||
} |
|||
|
|||
void addFragment(Fragment fragment, String title) { |
|||
fragmentList.add(fragment); |
|||
fragmentTitleList.add(title); |
|||
notifyDataSetChanged(); |
|||
} |
|||
|
|||
@Override |
|||
public Fragment getItem(int position) { |
|||
return fragmentList.get(position); |
|||
} |
|||
|
|||
@Override |
|||
public int getCount() { |
|||
return fragmentList.size(); |
|||
} |
|||
|
|||
@Override |
|||
public CharSequence getPageTitle(int position) { |
|||
return fragmentTitleList.get(position); |
|||
} |
|||
|
|||
@Override |
|||
public int getItemPosition(Object object) { |
|||
@SuppressWarnings("RedundantCast") |
|||
int position = fragmentList.indexOf((Fragment) object); |
|||
return position == -1 ? POSITION_NONE : position; |
|||
} |
|||
} |
|||
} |
@ -0,0 +1,163 @@ |
|||
package gr.thmmy.mthmmy.activities.bookmarks; |
|||
|
|||
import android.app.Activity; |
|||
import android.graphics.Typeface; |
|||
import android.graphics.drawable.Drawable; |
|||
import android.os.Build; |
|||
import android.os.Bundle; |
|||
import android.support.annotation.NonNull; |
|||
import android.support.graphics.drawable.VectorDrawableCompat; |
|||
import android.support.v4.app.Fragment; |
|||
import android.view.LayoutInflater; |
|||
import android.view.View; |
|||
import android.view.ViewGroup; |
|||
import android.widget.ImageButton; |
|||
import android.widget.LinearLayout; |
|||
import android.widget.TextView; |
|||
|
|||
import java.util.ArrayList; |
|||
|
|||
import gr.thmmy.mthmmy.R; |
|||
import gr.thmmy.mthmmy.model.Bookmark; |
|||
|
|||
public class TopicBookmarksFragment extends Fragment { |
|||
protected static final String ARG_SECTION_NUMBER = "SECTION_NUMBER"; |
|||
protected static final String ARG_TOPIC_BOOKMARKS = "BOARD_BOOKMARKS"; |
|||
|
|||
public static final String INTERACTION_CLICK_TOPIC_BOOKMARK = "CLICK_BOARD_BOOKMARK"; |
|||
public static final String INTERACTION_TOGGLE_TOPIC_NOTIFICATION = "TOGGLE_TOPIC_NOTIFICATION"; |
|||
public static final String INTERACTION_REMOVE_TOPIC_BOOKMARK = "REMOVE_BOARD_BOOKMARK"; |
|||
|
|||
ArrayList<Bookmark> topicBookmarks = null; |
|||
|
|||
private static Drawable notificationsEnabledButtonImage; |
|||
private static Drawable notificationsDisabledButtonImage; |
|||
|
|||
// Required empty public constructor
|
|||
public TopicBookmarksFragment() { |
|||
} |
|||
|
|||
/** |
|||
* Use ONLY this factory method to create a new instance of |
|||
* this fragment using the provided parameters. |
|||
* |
|||
* @return A new instance of fragment Forum. |
|||
*/ |
|||
public static TopicBookmarksFragment newInstance(int sectionNumber, String boardBookmarks) { |
|||
TopicBookmarksFragment fragment = new TopicBookmarksFragment(); |
|||
Bundle args = new Bundle(); |
|||
args.putInt(ARG_SECTION_NUMBER, sectionNumber); |
|||
args.putString(ARG_TOPIC_BOOKMARKS, boardBookmarks); |
|||
fragment.setArguments(args); |
|||
return fragment; |
|||
} |
|||
|
|||
@Override |
|||
public void onCreate(Bundle savedInstanceState) { |
|||
super.onCreate(savedInstanceState); |
|||
if (getArguments() != null) { |
|||
String bundledBoardBookmarks = getArguments().getString(ARG_TOPIC_BOOKMARKS); |
|||
if (bundledBoardBookmarks != null) { |
|||
topicBookmarks = Bookmark.arrayFromString(bundledBoardBookmarks); |
|||
} |
|||
} |
|||
|
|||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { |
|||
notificationsEnabledButtonImage = getResources().getDrawable(R.drawable.ic_notification_on, null); |
|||
} else { |
|||
notificationsEnabledButtonImage = VectorDrawableCompat.create(getResources(), R.drawable.ic_notification_on, null); |
|||
} |
|||
|
|||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { |
|||
notificationsDisabledButtonImage = getResources().getDrawable(R.drawable.ic_notification_off, null); |
|||
} else { |
|||
notificationsDisabledButtonImage = VectorDrawableCompat.create(getResources(), R.drawable.ic_notification_off, null); |
|||
} |
|||
} |
|||
|
|||
@Override |
|||
public View onCreateView(@NonNull LayoutInflater layoutInflater, ViewGroup container, |
|||
Bundle savedInstanceState) { |
|||
// Inflates the layout for this fragment
|
|||
final View rootView = layoutInflater.inflate(R.layout.fragment_bookmarks, container, false); |
|||
//bookmarks_board_container
|
|||
final LinearLayout bookmarksLinearView = rootView.findViewById(R.id.bookmarks_container); |
|||
|
|||
if(this.topicBookmarks != null && !this.topicBookmarks.isEmpty()) { |
|||
for (final Bookmark bookmarkedTopic : topicBookmarks) { |
|||
if (bookmarkedTopic != null && bookmarkedTopic.getTitle() != null) { |
|||
final LinearLayout row = (LinearLayout) layoutInflater.inflate( |
|||
R.layout.fragment_bookmarks_topic_row, bookmarksLinearView, false); |
|||
row.setOnClickListener(new View.OnClickListener() { |
|||
@Override |
|||
public void onClick(View view) { |
|||
Activity activity = getActivity(); |
|||
if (activity instanceof BookmarkActivity) { |
|||
((BookmarkActivity) activity).onTopicInteractionListener(INTERACTION_CLICK_TOPIC_BOOKMARK, bookmarkedTopic); |
|||
} |
|||
} |
|||
}); |
|||
((TextView) row.findViewById(R.id.bookmark_title)).setText(bookmarkedTopic.getTitle()); |
|||
|
|||
final ImageButton notificationsEnabledButton = row.findViewById(R.id.toggle_notification); |
|||
if (!bookmarkedTopic.isNotificationsEnabled()) { |
|||
notificationsEnabledButton.setImageDrawable(notificationsDisabledButtonImage); |
|||
} |
|||
|
|||
notificationsEnabledButton.setOnClickListener(new View.OnClickListener() { |
|||
@Override |
|||
public void onClick(View view) { |
|||
Activity activity = getActivity(); |
|||
if (activity instanceof BookmarkActivity) { |
|||
if (((BookmarkActivity) activity).onTopicInteractionListener(INTERACTION_TOGGLE_TOPIC_NOTIFICATION, bookmarkedTopic)) { |
|||
notificationsEnabledButton.setImageDrawable(notificationsEnabledButtonImage); |
|||
} else { |
|||
notificationsEnabledButton.setImageDrawable(notificationsDisabledButtonImage); |
|||
} |
|||
} |
|||
} |
|||
}); |
|||
(row.findViewById(R.id.remove_bookmark)).setOnClickListener(new View.OnClickListener() { |
|||
@Override |
|||
public void onClick(View view) { |
|||
Activity activity = getActivity(); |
|||
if (activity instanceof BookmarkActivity) { |
|||
((BookmarkActivity) activity).onTopicInteractionListener(INTERACTION_REMOVE_TOPIC_BOOKMARK, bookmarkedTopic); |
|||
topicBookmarks.remove(bookmarkedTopic); |
|||
} |
|||
row.setVisibility(View.GONE); |
|||
|
|||
if (topicBookmarks.isEmpty()){ |
|||
bookmarksLinearView.addView(bookmarksListEmptyMessage()); |
|||
} |
|||
} |
|||
}); |
|||
bookmarksLinearView.addView(row); |
|||
} |
|||
} |
|||
} else { |
|||
bookmarksLinearView.addView(bookmarksListEmptyMessage()); |
|||
} |
|||
|
|||
|
|||
return rootView; |
|||
} |
|||
|
|||
private TextView bookmarksListEmptyMessage() { |
|||
TextView emptyBookmarksCategory = new TextView(this.getContext()); |
|||
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams( |
|||
LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT); |
|||
params.setMargins(0, 12, 0, 0); |
|||
emptyBookmarksCategory.setLayoutParams(params); |
|||
emptyBookmarksCategory.setText(getString(R.string.empty_topic_bookmarks)); |
|||
emptyBookmarksCategory.setTypeface(emptyBookmarksCategory.getTypeface(), Typeface.BOLD); |
|||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { |
|||
emptyBookmarksCategory.setTextColor(this.getContext().getColor(R.color.primary_text)); |
|||
} else { |
|||
//noinspection deprecation
|
|||
emptyBookmarksCategory.setTextColor(this.getContext().getResources().getColor(R.color.primary_text)); |
|||
} |
|||
emptyBookmarksCategory.setTextAlignment(View.TEXT_ALIGNMENT_CENTER); |
|||
return emptyBookmarksCategory; |
|||
} |
|||
} |
@ -0,0 +1,81 @@ |
|||
package gr.thmmy.mthmmy.model; |
|||
|
|||
/** |
|||
* Class that defines the model of a post as need in notifications. All member variables are |
|||
* declared final (thus no setters are supplied). Class has one constructor and getter methods for |
|||
* all variables. |
|||
* <p>PostNotification model is described by its post's id, its topic's id & title and by its poster |
|||
* </p>. |
|||
*/ |
|||
public class PostNotification { |
|||
final int postId; |
|||
final int topicId; |
|||
final String topicTitle; |
|||
final String poster; |
|||
|
|||
// Suppresses default constructor
|
|||
@SuppressWarnings("unused") |
|||
PostNotification() { |
|||
this.postId = -1; |
|||
this.topicId = -1; |
|||
this.topicTitle = null; |
|||
this.poster = null; |
|||
} |
|||
|
|||
/** |
|||
* Constructor specifying all class variables necessary to summarize this post. All variables |
|||
* are declared final, once assigned they cannot change. |
|||
* |
|||
* @param postId this post's id |
|||
* @param topicId this post's topicId |
|||
* @param topicTitle this post's topicTitle |
|||
* @param poster username of this post's author |
|||
*/ |
|||
public PostNotification(int postId, int topicId, String topicTitle, String poster) { |
|||
this.postId = postId; |
|||
this.topicId = topicId; |
|||
this.topicTitle = topicTitle; |
|||
this.poster = poster; |
|||
} |
|||
|
|||
/** |
|||
* Gets this post's Id. |
|||
* |
|||
* @return this post's Id |
|||
*/ |
|||
public int getPostId() { |
|||
return postId; |
|||
} |
|||
|
|||
/** |
|||
* Gets this post's topicId. |
|||
* |
|||
* @return this post's topicId |
|||
*/ |
|||
public int getTopicId() { |
|||
return topicId; |
|||
} |
|||
|
|||
/** |
|||
* Gets this post's topicTitle. |
|||
* |
|||
* @return this post's topicTitle |
|||
*/ |
|||
public String getTopicTitle() { |
|||
return topicTitle; |
|||
} |
|||
|
|||
/** |
|||
* Gets username of this post's author. |
|||
* |
|||
* @return username of this post's author |
|||
*/ |
|||
public String getPoster() { |
|||
return poster; |
|||
} |
|||
} |
|||
|
|||
|
|||
|
|||
|
|||
|
@ -1,80 +0,0 @@ |
|||
package gr.thmmy.mthmmy.receiver; |
|||
|
|||
import android.app.Notification; |
|||
import android.app.NotificationManager; |
|||
import android.app.PendingIntent; |
|||
import android.content.BroadcastReceiver; |
|||
import android.content.Context; |
|||
import android.content.Intent; |
|||
import android.net.Uri; |
|||
import android.os.Bundle; |
|||
import android.support.v7.app.NotificationCompat; |
|||
import android.webkit.MimeTypeMap; |
|||
|
|||
import java.io.File; |
|||
|
|||
import timber.log.Timber; |
|||
|
|||
import static gr.thmmy.mthmmy.services.DownloadService.ACTION_DOWNLOAD; |
|||
import static gr.thmmy.mthmmy.services.DownloadService.COMPLETED; |
|||
import static gr.thmmy.mthmmy.services.DownloadService.EXTRA_DOWNLOAD_ID; |
|||
import static gr.thmmy.mthmmy.services.DownloadService.EXTRA_DOWNLOAD_STATE; |
|||
import static gr.thmmy.mthmmy.services.DownloadService.EXTRA_FILE_NAME; |
|||
import static gr.thmmy.mthmmy.services.DownloadService.EXTRA_NOTIFICATION_TEXT; |
|||
import static gr.thmmy.mthmmy.services.DownloadService.EXTRA_NOTIFICATION_TICKER; |
|||
import static gr.thmmy.mthmmy.services.DownloadService.EXTRA_NOTIFICATION_TITLE; |
|||
import static gr.thmmy.mthmmy.services.DownloadService.SAVE_DIR; |
|||
import static gr.thmmy.mthmmy.services.DownloadService.STARTED; |
|||
|
|||
public class Receiver extends BroadcastReceiver { |
|||
|
|||
public Receiver() {} |
|||
|
|||
@Override |
|||
public void onReceive(Context context, Intent intent) { |
|||
NotificationCompat.Builder builder = new NotificationCompat.Builder(context); |
|||
NotificationManager notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE); |
|||
|
|||
if (intent.getAction().equals(ACTION_DOWNLOAD)) { |
|||
Bundle extras = intent.getExtras(); |
|||
int id = extras.getInt(EXTRA_DOWNLOAD_ID); |
|||
String state = extras.getString(EXTRA_DOWNLOAD_STATE, "NONE"); |
|||
String title = extras.getString(EXTRA_NOTIFICATION_TITLE); |
|||
String text = extras.getString(EXTRA_NOTIFICATION_TEXT); |
|||
String ticker = extras.getString(EXTRA_NOTIFICATION_TICKER); |
|||
|
|||
builder.setContentTitle(title) |
|||
.setContentText(text) |
|||
.setTicker(ticker) |
|||
.setAutoCancel(true); |
|||
|
|||
if (state.equals(STARTED)) |
|||
builder.setOngoing(true) |
|||
.setSmallIcon(android.R.drawable.stat_sys_download); |
|||
else if (state.equals(COMPLETED)) { |
|||
String fileName = extras.getString(EXTRA_FILE_NAME, "NONE"); |
|||
|
|||
File file = new File(SAVE_DIR, fileName); |
|||
if (file.exists()) { |
|||
String type = MimeTypeMap.getSingleton().getMimeTypeFromExtension( |
|||
MimeTypeMap.getFileExtensionFromUrl(file.getAbsolutePath())); |
|||
|
|||
|
|||
Intent chooserIntent = new Intent(Intent.ACTION_VIEW); |
|||
chooserIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); |
|||
chooserIntent.setDataAndType(Uri.fromFile(file), type); |
|||
Intent chooser = Intent.createChooser(chooserIntent, "Open With..."); |
|||
|
|||
PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, chooser, PendingIntent.FLAG_CANCEL_CURRENT); |
|||
builder.setContentIntent(pendingIntent) |
|||
.setSmallIcon(android.R.drawable.stat_sys_download_done); |
|||
|
|||
} else |
|||
Timber.w("File doesn't exist."); |
|||
} |
|||
Notification notification = builder.build(); |
|||
notificationManager.notify(id, notification); |
|||
} |
|||
} |
|||
|
|||
} |
@ -0,0 +1,73 @@ |
|||
package gr.thmmy.mthmmy.services; |
|||
|
|||
import android.app.DownloadManager; |
|||
import android.content.Context; |
|||
import android.net.Uri; |
|||
import android.os.Environment; |
|||
import android.widget.Toast; |
|||
|
|||
import java.io.File; |
|||
|
|||
import gr.thmmy.mthmmy.base.BaseApplication; |
|||
import gr.thmmy.mthmmy.model.ThmmyFile; |
|||
import okhttp3.Cookie; |
|||
import timber.log.Timber; |
|||
|
|||
import static gr.thmmy.mthmmy.utils.FileUtils.getMimeType; |
|||
|
|||
/** |
|||
* Not an actual service, but simply a helper class that adds a download to the queue of Android's |
|||
* DownloadManager system service. |
|||
*/ |
|||
public class DownloadHelper { |
|||
public static final File SAVE_DIR = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS); |
|||
|
|||
public static void enqueueDownload(ThmmyFile thmmyFile){ |
|||
Context applicationContext = BaseApplication.getInstance().getApplicationContext(); |
|||
Toast.makeText(applicationContext, "Download started!", Toast.LENGTH_SHORT).show(); |
|||
|
|||
try { |
|||
String fileName = renameFileIfExists(thmmyFile.getFilename()); |
|||
Uri downloadURI = Uri.parse(thmmyFile.getFileUrl().toString()); |
|||
|
|||
DownloadManager downloadManager = (DownloadManager)applicationContext.getSystemService(Context.DOWNLOAD_SERVICE); |
|||
DownloadManager.Request request = new DownloadManager.Request(downloadURI); |
|||
|
|||
Cookie thmmyCookie = BaseApplication.getInstance().getSessionManager().getThmmyCookie(); |
|||
request.addRequestHeader("Cookie", thmmyCookie.name() + "=" + thmmyCookie.value()); |
|||
request.setTitle(fileName); |
|||
request.setMimeType(getMimeType(fileName)); |
|||
request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED); |
|||
request.setDestinationInExternalPublicDir(SAVE_DIR.getName(), fileName); |
|||
request.allowScanningByMediaScanner(); |
|||
|
|||
downloadManager.enqueue(request); |
|||
} catch (Exception e) { |
|||
Toast.makeText(applicationContext, "Download failed...", Toast.LENGTH_SHORT).show(); |
|||
Timber.e(e, "Exception while enqueuing download."); |
|||
} |
|||
} |
|||
|
|||
private static String renameFileIfExists(String originalFileName) { |
|||
final String dirPath = SAVE_DIR.getAbsolutePath(); |
|||
File file = new File(dirPath, originalFileName); |
|||
|
|||
String nameFormat; |
|||
String[] tokens = originalFileName.split("\\.(?=[^.]+$)"); |
|||
|
|||
if (tokens.length != 2) { |
|||
Timber.w("Couldn't get file extension..."); |
|||
nameFormat = originalFileName + "(%d)"; |
|||
} else |
|||
nameFormat = tokens[0] + "-%d." + tokens[1]; |
|||
|
|||
for (int i = 1; ; i++) { |
|||
if (!file.isFile()) |
|||
break; |
|||
|
|||
file = new File(dirPath, String.format(nameFormat, i)); |
|||
} |
|||
|
|||
return file.getName(); |
|||
} |
|||
} |
@ -1,228 +0,0 @@ |
|||
package gr.thmmy.mthmmy.services; |
|||
|
|||
import android.app.DownloadManager; |
|||
import android.app.IntentService; |
|||
import android.content.Context; |
|||
import android.content.Intent; |
|||
import android.content.IntentFilter; |
|||
import android.os.Environment; |
|||
import android.support.annotation.NonNull; |
|||
import android.webkit.MimeTypeMap; |
|||
|
|||
import java.io.File; |
|||
import java.io.FileNotFoundException; |
|||
import java.io.IOException; |
|||
|
|||
import gr.thmmy.mthmmy.base.BaseApplication; |
|||
import gr.thmmy.mthmmy.receiver.Receiver; |
|||
import okhttp3.OkHttpClient; |
|||
import okhttp3.Request; |
|||
import okhttp3.Response; |
|||
import okio.BufferedSink; |
|||
import okio.Okio; |
|||
import timber.log.Timber; |
|||
|
|||
/** |
|||
* An {@link IntentService} subclass for handling asynchronous task requests in |
|||
* a service on a separate handler thread. |
|||
*/ |
|||
public class DownloadService extends IntentService { |
|||
private static final String TAG = "DownloadService"; |
|||
private static int sDownloadId = 0; |
|||
|
|||
private Receiver receiver; |
|||
|
|||
public static final String SAVE_DIR = Environment.getExternalStorageDirectory().getAbsolutePath() + File.separator + "mthmmy"; |
|||
|
|||
public static final String ACTION_DOWNLOAD = "gr.thmmy.mthmmy.services.action.DOWNLOAD"; |
|||
public static final String EXTRA_DOWNLOAD_URL = "gr.thmmy.mthmmy.services.extra.DOWNLOAD_URL"; |
|||
|
|||
public static final String EXTRA_DOWNLOAD_ID = "gr.thmmy.mthmmy.services.extra.DOWNLOAD_ID"; |
|||
public static final String EXTRA_DOWNLOAD_STATE = "gr.thmmy.mthmmy.services.extra.DOWNLOAD_STATE"; |
|||
public static final String EXTRA_FILE_NAME = "gr.thmmy.mthmmy.services.extra.FILE_NAME"; |
|||
public static final String EXTRA_NOTIFICATION_TITLE = "gr.thmmy.mthmmy.services.extra.NOTIFICATION_TITLE"; |
|||
public static final String EXTRA_NOTIFICATION_TEXT = "gr.thmmy.mthmmy.services.extra.NOTIFICATION_TEXT"; |
|||
public static final String EXTRA_NOTIFICATION_TICKER = "gr.thmmy.mthmmy.services.extra.NOTIFICATION_TICKER"; |
|||
|
|||
public static final String STARTED = "Started"; |
|||
public static final String COMPLETED = "Completed"; |
|||
public static final String FAILED = "Failed"; |
|||
|
|||
|
|||
public DownloadService() { |
|||
super("DownloadService"); |
|||
} |
|||
|
|||
@Override |
|||
public void onCreate() { |
|||
super.onCreate(); |
|||
final IntentFilter filter = new IntentFilter(DownloadService.ACTION_DOWNLOAD); |
|||
receiver = new Receiver(); |
|||
registerReceiver(receiver, filter); |
|||
|
|||
} |
|||
|
|||
@Override |
|||
public void onDestroy() { |
|||
super.onDestroy(); |
|||
this.unregisterReceiver(receiver); |
|||
} |
|||
|
|||
/** |
|||
* Starts this service to perform action Download with the given parameters. If |
|||
* the service is already performing a task this action will be queued. |
|||
* |
|||
* @see IntentService |
|||
*/ |
|||
public static void startActionDownload(Context context, String downloadUrl) { |
|||
Intent intent = new Intent(context, DownloadService.class); |
|||
intent.setAction(ACTION_DOWNLOAD); |
|||
intent.putExtra(EXTRA_DOWNLOAD_URL, downloadUrl); |
|||
context.startService(intent); |
|||
} |
|||
|
|||
@Override |
|||
protected void onHandleIntent(Intent intent) { |
|||
if (intent != null) { |
|||
final String action = intent.getAction(); |
|||
if (ACTION_DOWNLOAD.equals(action)) { |
|||
final String downloadLink = intent.getStringExtra(EXTRA_DOWNLOAD_URL); |
|||
handleActionDownload(downloadLink); |
|||
} |
|||
} |
|||
} |
|||
|
|||
/** |
|||
* Handle action Foo in the provided background thread with the provided |
|||
* parameters. |
|||
*/ |
|||
private void handleActionDownload(String downloadLink) { |
|||
OkHttpClient client = BaseApplication.getInstance().getClient(); |
|||
BufferedSink sink = null; |
|||
String fileName = "file"; |
|||
|
|||
int downloadId = sDownloadId; |
|||
sDownloadId++; |
|||
|
|||
try { |
|||
Request request = new Request.Builder().url(downloadLink).build(); |
|||
Response response = client.newCall(request).execute(); |
|||
|
|||
String contentDisposition = response.headers("Content-Disposition").toString(); //check if link provides an attachment
|
|||
if (contentDisposition.contains("attachment")) { |
|||
fileName = contentDisposition.split("\"")[1]; |
|||
|
|||
File dirPath = new File(SAVE_DIR); |
|||
if (!dirPath.isDirectory()) { |
|||
if (dirPath.mkdirs()) |
|||
Timber.i("mTHMMY's directory created successfully!"); |
|||
else |
|||
Timber.e("Couldn't create mTHMMY's directory..."); |
|||
} |
|||
|
|||
|
|||
String nameFormat; |
|||
String[] tokens = fileName.split("\\.(?=[^\\.]+$)"); |
|||
|
|||
if (tokens.length != 2) { |
|||
Timber.w("Couldn't get file extension..."); |
|||
nameFormat = fileName + "(%d)"; |
|||
} else |
|||
nameFormat = tokens[0] + "(%d)." + tokens[1]; |
|||
|
|||
|
|||
File file = new File(dirPath, fileName); |
|||
|
|||
for (int i = 1; ; i++) { |
|||
if (!file.exists()) { |
|||
break; |
|||
} |
|||
|
|||
file = new File(dirPath, String.format(nameFormat, i)); |
|||
} |
|||
|
|||
fileName = file.getName(); |
|||
|
|||
Timber.v("Started saving file %s", fileName); |
|||
sendNotification(downloadId, STARTED, fileName); |
|||
|
|||
sink = Okio.buffer(Okio.sink(file)); |
|||
sink.writeAll(response.body().source()); |
|||
sink.flush(); |
|||
Timber.i("Download OK!"); |
|||
sendNotification(downloadId, COMPLETED, fileName); |
|||
|
|||
// Register download
|
|||
DownloadManager mManager = (DownloadManager) getSystemService(Context.DOWNLOAD_SERVICE); |
|||
long length = file.length(); |
|||
mManager.addCompletedDownload(fileName, "edo mporei na mpei ena description", false, getMimeType(file), SAVE_DIR +File.separator+ fileName, length, false); |
|||
|
|||
} else |
|||
Timber.e("No attachment in response!"); |
|||
} catch (FileNotFoundException e) { |
|||
Timber.i("Download failed..."); |
|||
Timber.e(e, "FileNotFound"); |
|||
sendNotification(downloadId, FAILED, fileName); |
|||
} catch (IOException e) { |
|||
Timber.i("Download failed..."); |
|||
Timber.e(e, "IOException"); |
|||
sendNotification(downloadId, FAILED, fileName); |
|||
} finally { |
|||
if (sink != null) { |
|||
try { |
|||
sink.close(); |
|||
} catch (IOException e) { |
|||
// Ignore - Significant errors should already have been reported
|
|||
} |
|||
} |
|||
} |
|||
} |
|||
|
|||
private void sendNotification(int downloadId, String type, @NonNull String fileName) { |
|||
Intent intent = new Intent(ACTION_DOWNLOAD); |
|||
switch (type) { |
|||
case STARTED: { |
|||
intent.putExtra(EXTRA_NOTIFICATION_TITLE, "Download Started"); |
|||
intent.putExtra(EXTRA_NOTIFICATION_TEXT, "\"" + fileName + "\" downloading..."); |
|||
intent.putExtra(EXTRA_NOTIFICATION_TICKER, "Downloading..."); |
|||
break; |
|||
} |
|||
case COMPLETED: { |
|||
intent.putExtra(EXTRA_NOTIFICATION_TITLE, "Download Completed"); |
|||
intent.putExtra(EXTRA_NOTIFICATION_TEXT, "\"" + fileName + "\" finished downloading."); |
|||
intent.putExtra(EXTRA_NOTIFICATION_TICKER, "Download Completed"); |
|||
break; |
|||
} |
|||
case FAILED: { |
|||
intent.putExtra(EXTRA_NOTIFICATION_TITLE, "Download Failed"); |
|||
intent.putExtra(EXTRA_NOTIFICATION_TEXT, "\"" + fileName + "\" failed."); |
|||
intent.putExtra(EXTRA_NOTIFICATION_TICKER, "Download Failed"); |
|||
break; |
|||
} |
|||
default: { |
|||
Timber.e("Invalid notification case!"); |
|||
return; |
|||
} |
|||
} |
|||
intent.putExtra(EXTRA_DOWNLOAD_ID, downloadId); |
|||
intent.putExtra(EXTRA_DOWNLOAD_STATE, type); |
|||
intent.putExtra(EXTRA_FILE_NAME, fileName); |
|||
sendBroadcast(intent); |
|||
|
|||
} |
|||
|
|||
@NonNull |
|||
static String getMimeType(@NonNull File file) { |
|||
String type = null; |
|||
final String url = file.toString(); |
|||
final String extension = MimeTypeMap.getFileExtensionFromUrl(url); |
|||
if (extension != null) { |
|||
type = MimeTypeMap.getSingleton().getMimeTypeFromExtension(extension.toLowerCase()); |
|||
} |
|||
if (type == null) { |
|||
type = ""; // fallback type. You might set it to */*
|
|||
} |
|||
return type; |
|||
} |
|||
|
|||
} |
@ -0,0 +1,203 @@ |
|||
package gr.thmmy.mthmmy.services; |
|||
|
|||
import android.app.Notification; |
|||
import android.app.NotificationChannel; |
|||
import android.app.NotificationManager; |
|||
import android.app.PendingIntent; |
|||
import android.content.Context; |
|||
import android.content.Intent; |
|||
import android.os.Build; |
|||
import android.os.Bundle; |
|||
import android.service.notification.StatusBarNotification; |
|||
import android.support.annotation.RequiresApi; |
|||
import android.support.v4.app.NotificationCompat; |
|||
|
|||
import com.google.firebase.messaging.FirebaseMessagingService; |
|||
import com.google.firebase.messaging.RemoteMessage; |
|||
|
|||
import org.json.JSONException; |
|||
import org.json.JSONObject; |
|||
|
|||
import gr.thmmy.mthmmy.R; |
|||
import gr.thmmy.mthmmy.activities.topic.TopicActivity; |
|||
import gr.thmmy.mthmmy.base.BaseApplication; |
|||
import gr.thmmy.mthmmy.model.PostNotification; |
|||
import timber.log.Timber; |
|||
|
|||
import static android.support.v4.app.NotificationCompat.PRIORITY_MAX; |
|||
import static gr.thmmy.mthmmy.activities.topic.TopicActivity.BUNDLE_TOPIC_TITLE; |
|||
import static gr.thmmy.mthmmy.activities.topic.TopicActivity.BUNDLE_TOPIC_URL; |
|||
|
|||
public class NotificationService extends FirebaseMessagingService { |
|||
private static final int buildVersion = Build.VERSION.SDK_INT; |
|||
|
|||
@Override |
|||
public void onMessageReceived(RemoteMessage remoteMessage) { |
|||
super.onMessageReceived(remoteMessage); |
|||
if (remoteMessage.getData().size() > 0) { |
|||
Timber.i("FCM data message received."); |
|||
JSONObject json = new JSONObject(remoteMessage.getData()); |
|||
try { |
|||
int userId = BaseApplication.getInstance().getSessionManager().getUserId(); |
|||
//Don't notify me if the sender is me!
|
|||
if(Integer.parseInt(json.getString("posterId"))!= userId) |
|||
{ |
|||
int topicId = Integer.parseInt(json.getString("topicId")); |
|||
int postId = Integer.parseInt(json.getString("postId")); |
|||
String topicTitle = json.getString("topicTitle"); |
|||
String poster = json.getString("poster"); |
|||
sendNotification(new PostNotification(postId, topicId, topicTitle, poster)); |
|||
} |
|||
else |
|||
Timber.v("Notification suppressed (own userID)."); |
|||
} catch (JSONException e) { |
|||
Timber.e(e, "JSON Exception"); |
|||
} |
|||
} |
|||
} |
|||
|
|||
private static final String CHANNEL_ID = "Posts"; |
|||
private static final String CHANNEL_NAME = "New Posts"; |
|||
private static final String GROUP_KEY = "PostsGroup"; |
|||
private static int requestCode = 0; |
|||
|
|||
private static final String NEW_POSTS_COUNT = "newPostsCount"; |
|||
public static final String NEW_POST_TAG = "NEW_POST"; |
|||
private static final String SUMMARY_TAG = "SUMMARY"; |
|||
private static final String DELETED_MESSAGES_TAG = "DELETED_MESSAGES"; |
|||
|
|||
/** |
|||
* Create and show a new post notification. |
|||
*/ |
|||
private void sendNotification(PostNotification postNotification) { |
|||
Timber.i("Creating a notification..."); |
|||
String topicUrl = "https://www.thmmy.gr/smf/index.php?topic=" + postNotification.getTopicId() + "." + postNotification.getPostId(); |
|||
Intent intent = new Intent(this, TopicActivity.class); |
|||
Bundle extras = new Bundle(); |
|||
extras.putString(BUNDLE_TOPIC_URL, topicUrl); |
|||
extras.putString(BUNDLE_TOPIC_TITLE, postNotification.getTopicTitle()); |
|||
intent.putExtras(extras); |
|||
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); |
|||
PendingIntent pendingIntent = PendingIntent.getActivity(this, requestCode++, intent, |
|||
PendingIntent.FLAG_ONE_SHOT); |
|||
|
|||
final int topicId = postNotification.getTopicId(); |
|||
String contentText = "New post by " + postNotification.getPoster(); |
|||
int newPostsCount = 1; |
|||
|
|||
if (buildVersion >= Build.VERSION_CODES.M){ |
|||
Notification existingNotification = getActiveNotification(topicId); |
|||
if(existingNotification!=null) |
|||
{ |
|||
newPostsCount = existingNotification.extras.getInt(NEW_POSTS_COUNT) + 1; |
|||
contentText = newPostsCount + " new posts"; |
|||
} |
|||
} |
|||
|
|||
Bundle notificationExtras = new Bundle(); |
|||
notificationExtras.putInt(NEW_POSTS_COUNT, newPostsCount); |
|||
|
|||
NotificationCompat.Builder notificationBuilder = |
|||
new NotificationCompat.Builder(this, CHANNEL_ID) |
|||
.setSmallIcon(R.mipmap.ic_launcher) |
|||
.setContentTitle(postNotification.getTopicTitle()) |
|||
.setContentText(contentText) |
|||
.setAutoCancel(true) |
|||
.setContentIntent(pendingIntent) |
|||
.setDefaults(Notification.DEFAULT_ALL) |
|||
.setGroup(GROUP_KEY) |
|||
.addExtras(notificationExtras); |
|||
|
|||
if (buildVersion < Build.VERSION_CODES.O) |
|||
notificationBuilder.setPriority(PRIORITY_MAX); |
|||
|
|||
boolean createSummaryNotification = false; |
|||
if(buildVersion >= Build.VERSION_CODES.LOLLIPOP) |
|||
{ |
|||
createSummaryNotification = true; |
|||
if(buildVersion >= Build.VERSION_CODES.M) |
|||
createSummaryNotification = otherNotificationsExist(topicId); |
|||
} |
|||
|
|||
NotificationCompat.Builder summaryNotificationBuilder = null; |
|||
if(createSummaryNotification) |
|||
{ |
|||
summaryNotificationBuilder = |
|||
new NotificationCompat.Builder(this, CHANNEL_ID) |
|||
.setSmallIcon(R.mipmap.ic_launcher) |
|||
.setGroupSummary(true) |
|||
.setGroup(GROUP_KEY) |
|||
.setAutoCancel(true) |
|||
.setStyle(new NotificationCompat.InboxStyle() |
|||
.setSummaryText("New Posts")) |
|||
.setDefaults(Notification.DEFAULT_ALL); |
|||
} |
|||
|
|||
|
|||
|
|||
|
|||
NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE); |
|||
|
|||
// Since Android Oreo notification channel is needed.
|
|||
if (buildVersion >= Build.VERSION_CODES.O) |
|||
notificationManager.createNotificationChannel(new NotificationChannel(CHANNEL_ID, CHANNEL_NAME, NotificationManager.IMPORTANCE_HIGH)); |
|||
|
|||
notificationManager.notify(NEW_POST_TAG, topicId, notificationBuilder.build()); |
|||
|
|||
if(createSummaryNotification) |
|||
notificationManager.notify(SUMMARY_TAG,0, summaryNotificationBuilder.build()); |
|||
} |
|||
|
|||
@RequiresApi(api = Build.VERSION_CODES.M) |
|||
private Notification getActiveNotification(int notificationId) { |
|||
NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE); |
|||
if(notificationManager!=null) |
|||
{ |
|||
StatusBarNotification[] barNotifications = notificationManager.getActiveNotifications(); |
|||
for(StatusBarNotification notification: barNotifications) { |
|||
if (notification.getId() == notificationId) |
|||
return notification.getNotification(); |
|||
} |
|||
|
|||
} |
|||
return null; |
|||
} |
|||
|
|||
@RequiresApi(api = Build.VERSION_CODES.M) |
|||
private boolean otherNotificationsExist(int notificationId){ |
|||
NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE); |
|||
if(notificationManager!=null) { |
|||
StatusBarNotification[] barNotifications = notificationManager.getActiveNotifications(); |
|||
for (StatusBarNotification notification : barNotifications) { |
|||
String tag = notification.getTag(); |
|||
if (tag!=null && tag.equals(NEW_POST_TAG) && notification.getId() != notificationId) |
|||
return true; |
|||
} |
|||
} |
|||
return false; |
|||
} |
|||
|
|||
@Override |
|||
public void onDeletedMessages() { |
|||
super.onDeletedMessages(); |
|||
NotificationCompat.Builder notificationBuilder = |
|||
new NotificationCompat.Builder(this, CHANNEL_ID) |
|||
.setSmallIcon(R.mipmap.ic_launcher) |
|||
.setContentTitle("Error fetching notifications!") |
|||
.setContentText("Some notifications may not have arrived successfully either due to" + |
|||
"the amount of pending messages (>100) or if the device hasn't come online for more than a month.") |
|||
.setAutoCancel(true) |
|||
.setDefaults(Notification.DEFAULT_ALL); |
|||
|
|||
if (buildVersion < Build.VERSION_CODES.O) |
|||
notificationBuilder.setPriority(Notification.PRIORITY_MAX); |
|||
|
|||
NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE); |
|||
|
|||
// Since Android Oreo notification channel is needed.
|
|||
if (buildVersion >= Build.VERSION_CODES.O) |
|||
notificationManager.createNotificationChannel(new NotificationChannel(CHANNEL_ID, CHANNEL_NAME, NotificationManager.IMPORTANCE_HIGH)); |
|||
|
|||
notificationManager.notify(DELETED_MESSAGES_TAG, 0, notificationBuilder.build()); |
|||
} |
|||
} |
@ -0,0 +1,26 @@ |
|||
package gr.thmmy.mthmmy.utils; |
|||
|
|||
import android.support.annotation.NonNull; |
|||
import android.webkit.MimeTypeMap; |
|||
|
|||
import java.io.File; |
|||
|
|||
import static gr.thmmy.mthmmy.services.DownloadHelper.SAVE_DIR; |
|||
|
|||
public class FileUtils { |
|||
@NonNull |
|||
public static String getMimeType(@NonNull String fileName) { |
|||
String type = null; |
|||
final String extension = MimeTypeMap.getFileExtensionFromUrl(fileName); |
|||
if (extension != null) |
|||
type = MimeTypeMap.getSingleton().getMimeTypeFromExtension(extension.toLowerCase()); |
|||
if (type == null) |
|||
type = "*/*"; |
|||
|
|||
return type; |
|||
} |
|||
|
|||
public static boolean fileNameExists (String fileName) { |
|||
return fileName != null && (new File(SAVE_DIR.getAbsolutePath(), fileName)).isFile(); |
|||
} |
|||
} |
@ -1,4 +1,4 @@ |
|||
package gr.thmmy.mthmmy.utils.exceptions; |
|||
package gr.thmmy.mthmmy.utils.parsing; |
|||
|
|||
/** |
|||
* ParseException is to be used for errors while parsing. |
@ -1,4 +1,4 @@ |
|||
package gr.thmmy.mthmmy.utils; |
|||
package gr.thmmy.mthmmy.utils.parsing; |
|||
|
|||
import org.jsoup.nodes.Document; |
|||
import org.jsoup.nodes.Element; |
After Width: | Height: | Size: 198 B |
Before Width: | Height: | Size: 392 B |
After Width: | Height: | Size: 541 B |
After Width: | Height: | Size: 132 B |
Before Width: | Height: | Size: 270 B |
After Width: | Height: | Size: 365 B |
After Width: | Height: | Size: 196 B |
Before Width: | Height: | Size: 509 B |
After Width: | Height: | Size: 675 B |
After Width: | Height: | Size: 279 B |
Before Width: | Height: | Size: 746 B |
After Width: | Height: | Size: 1.0 KiB |
After Width: | Height: | Size: 357 B |
Before Width: | Height: | Size: 1.0 KiB |
After Width: | Height: | Size: 1.4 KiB |
@ -0,0 +1,9 @@ |
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android" |
|||
android:width="24dp" |
|||
android:height="24dp" |
|||
android:viewportWidth="24.0" |
|||
android:viewportHeight="24.0"> |
|||
<path |
|||
android:fillColor="#26A69A" |
|||
android:pathData="M12,22c1.1,0 2,-0.9 2,-2h-4c0,1.1 0.9,2 2,2zM18,16v-5c0,-3.07 -1.63,-5.64 -4.5,-6.32L13.5,4c0,-0.83 -0.67,-1.5 -1.5,-1.5s-1.5,0.67 -1.5,1.5v0.68C7.64,5.36 6,7.92 6,11v5l-2,2v1h16v-1l-2,-2zM16,17L8,17v-6c0,-2.48 1.51,-4.5 4,-4.5s4,2.02 4,4.5v6z"/> |
|||
</vector> |
@ -0,0 +1,5 @@ |
|||
<vector android:height="24dp" |
|||
android:viewportHeight="24.0" android:viewportWidth="24.0" |
|||
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android"> |
|||
<path android:fillColor="#26A69A" android:pathData="M7.58,4.08L6.15,2.65C3.75,4.48 2.17,7.3 2.03,10.5h2c0.15,-2.65 1.51,-4.97 3.55,-6.42zM19.97,10.5h2c-0.15,-3.2 -1.73,-6.02 -4.12,-7.85l-1.42,1.43c2.02,1.45 3.39,3.77 3.54,6.42zM18,11c0,-3.07 -1.64,-5.64 -4.5,-6.32L13.5,4c0,-0.83 -0.67,-1.5 -1.5,-1.5s-1.5,0.67 -1.5,1.5v0.68C7.63,5.36 6,7.92 6,11v5l-2,2v1h16v-1l-2,-2v-5zM12,22c0.14,0 0.27,-0.01 0.4,-0.04 0.65,-0.14 1.18,-0.58 1.44,-1.18 0.1,-0.24 0.15,-0.5 0.15,-0.78h-4c0.01,1.1 0.9,2 2.01,2z"/> |
|||
</vector> |
@ -0,0 +1,48 @@ |
|||
<?xml version="1.0" encoding="utf-8"?> |
|||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" |
|||
android:layout_width="match_parent" |
|||
android:layout_height="match_parent" |
|||
android:orientation="vertical" |
|||
android:background="@color/primary_light" |
|||
android:padding="4dp"> |
|||
|
|||
|
|||
<TextView |
|||
android:id="@+id/downloadPromptTextView" |
|||
android:layout_width="match_parent" |
|||
android:layout_height="wrap_content" |
|||
android:layout_weight="1" |
|||
android:padding="8dp" |
|||
android:textSize="16sp" |
|||
android:textColor="@color/white" /> |
|||
|
|||
<LinearLayout |
|||
android:layout_width="match_parent" |
|||
android:layout_height="wrap_content" |
|||
android:layout_weight="1" |
|||
android:orientation="horizontal"> |
|||
|
|||
<Button |
|||
android:id="@+id/cancel" |
|||
android:layout_width="wrap_content" |
|||
android:layout_height="wrap_content" |
|||
android:layout_weight="1" |
|||
style="?android:attr/borderlessButtonStyle" |
|||
android:text="@string/cancel" /> |
|||
|
|||
<Button |
|||
android:id="@+id/open" |
|||
android:layout_width="wrap_content" |
|||
android:layout_height="wrap_content" |
|||
android:layout_weight="1" |
|||
android:text="@string/open" /> |
|||
|
|||
<Button |
|||
android:id="@+id/download" |
|||
android:layout_width="wrap_content" |
|||
android:layout_height="wrap_content" |
|||
android:layout_weight="1" |
|||
android:text="@string/download" /> |
|||
</LinearLayout> |
|||
|
|||
</LinearLayout> |
@ -0,0 +1,25 @@ |
|||
<?xml version="1.0" encoding="utf-8"?> |
|||
<RelativeLayout |
|||
xmlns:android="http://schemas.android.com/apk/res/android" |
|||
xmlns:app="http://schemas.android.com/apk/res-auto" |
|||
android:layout_width="match_parent" android:layout_height="match_parent"> |
|||
|
|||
<android.support.v4.widget.NestedScrollView |
|||
android:id="@+id/bookmarks_nested_scroll" |
|||
android:layout_width="match_parent" |
|||
android:layout_height="match_parent" |
|||
android:layout_gravity="top|start" |
|||
android:background="@color/primary_light" |
|||
android:scrollbars="none" |
|||
app:layout_behavior="@string/appbar_scrolling_view_behavior"> |
|||
|
|||
<LinearLayout |
|||
android:id="@+id/bookmarks_container" |
|||
android:layout_width="match_parent" |
|||
android:layout_height="match_parent" |
|||
android:orientation="vertical" |
|||
android:showDividers="middle" |
|||
android:divider="?android:listDivider" |
|||
android:dividerPadding="16dp"/> |
|||
</android.support.v4.widget.NestedScrollView> |
|||
</RelativeLayout> |
@ -0,0 +1,50 @@ |
|||
<?xml version="1.0" encoding="utf-8"?> |
|||
<LinearLayout |
|||
xmlns:android="http://schemas.android.com/apk/res/android" |
|||
xmlns:app="http://schemas.android.com/apk/res-auto" |
|||
android:id="@+id/bookmark_row" |
|||
android:layout_width="match_parent" |
|||
android:layout_height="wrap_content" |
|||
android:background="?android:attr/selectableItemBackground" |
|||
android:clickable="true" |
|||
android:focusable="true" |
|||
android:gravity="center_vertical" |
|||
android:orientation="horizontal"> |
|||
|
|||
<TextView |
|||
android:id="@+id/bookmark_title" |
|||
android:layout_width="0dp" |
|||
android:layout_height="wrap_content" |
|||
android:layout_weight="1" |
|||
android:paddingBottom="8dp" |
|||
android:paddingTop="6dp" |
|||
android:paddingStart="16dp" |
|||
android:paddingEnd="0dp" |
|||
android:textColor="@color/primary_text" |
|||
android:textSize="18sp"/> |
|||
|
|||
<ImageButton |
|||
android:id="@+id/toggle_notification" |
|||
android:layout_width="wrap_content" |
|||
android:layout_height="match_parent" |
|||
android:paddingBottom="3dp" |
|||
android:paddingTop="3dp" |
|||
android:paddingStart="6dp" |
|||
android:paddingEnd="6dp" |
|||
android:background="@android:color/transparent" |
|||
android:contentDescription="@string/toggle_notification" |
|||
app:srcCompat="@drawable/ic_notification_on"/> |
|||
|
|||
<ImageButton |
|||
android:id="@+id/remove_bookmark" |
|||
android:layout_width="wrap_content" |
|||
android:layout_height="match_parent" |
|||
android:paddingBottom="3dp" |
|||
android:paddingTop="3dp" |
|||
android:paddingStart="6dp" |
|||
android:paddingEnd="6dp" |
|||
android:layout_marginEnd="12dp" |
|||
android:background="@android:color/transparent" |
|||
android:contentDescription="@string/remove_bookmark" |
|||
android:src="@drawable/ic_delete"/> |
|||
</LinearLayout> |
@ -1,10 +1,4 @@ |
|||
<?xml version="1.0" encoding="utf-8"?> |
|||
<paths> |
|||
<external-path |
|||
name="my_downloads" |
|||
path="Downloads/"/> |
|||
|
|||
<files-path |
|||
name="my_downloads" |
|||
path="Downloads/"/> |
|||
<external-path name="my_downloads" path="."/> |
|||
</paths> |
@ -1,6 +1,6 @@ |
|||
#Thu Oct 26 11:21:06 EEST 2017 |
|||
#Sat Apr 07 11:11:36 EEST 2018 |
|||
distributionBase=GRADLE_USER_HOME |
|||
distributionPath=wrapper/dists |
|||
zipStoreBase=GRADLE_USER_HOME |
|||
zipStorePath=wrapper/dists |
|||
distributionUrl=https\://services.gradle.org/distributions/gradle-4.1-all.zip |
|||
distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-all.zip |
|||
|