@ -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. |
* 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.Document; |
||||
import org.jsoup.nodes.Element; |
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"?> |
<?xml version="1.0" encoding="utf-8"?> |
||||
<paths> |
<paths> |
||||
<external-path |
<external-path name="my_downloads" path="."/> |
||||
name="my_downloads" |
|
||||
path="Downloads/"/> |
|
||||
|
|
||||
<files-path |
|
||||
name="my_downloads" |
|
||||
path="Downloads/"/> |
|
||||
</paths> |
</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 |
distributionBase=GRADLE_USER_HOME |
||||
distributionPath=wrapper/dists |
distributionPath=wrapper/dists |
||||
zipStoreBase=GRADLE_USER_HOME |
zipStoreBase=GRADLE_USER_HOME |
||||
zipStorePath=wrapper/dists |
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 |
||||
|