mirror of https://github.com/ThmmyNoLife/mTHMMY
Browse Source
# Conflicts: # app/build.gradle # app/src/main/java/gr/thmmy/mthmmy/activities/AboutActivity.java # app/src/main/java/gr/thmmy/mthmmy/activities/bookmarks/BoardBookmarksFragment.java # app/src/main/java/gr/thmmy/mthmmy/activities/downloads/DownloadsActivity.java # app/src/main/java/gr/thmmy/mthmmy/activities/topic/TopicAdapter.java # app/src/main/java/gr/thmmy/mthmmy/base/BaseActivity.java # app/src/main/java/gr/thmmy/mthmmy/base/BaseApplication.java # app/src/main/java/gr/thmmy/mthmmy/editorview/EditorView.java # app/src/main/res/layout/activity_downloads.xml # app/src/main/res/xml/app_preferences_user.xml # build.gradlepull/61/merge
Thodoris1999
6 years ago
103 changed files with 1316 additions and 367 deletions
@ -0,0 +1,50 @@ |
|||||
|
package gr.thmmy.mthmmy.activities.shoutbox; |
||||
|
|
||||
|
import org.jsoup.nodes.Document; |
||||
|
|
||||
|
import java.io.IOException; |
||||
|
|
||||
|
import gr.thmmy.mthmmy.utils.NetworkResultCodes; |
||||
|
import gr.thmmy.mthmmy.utils.NetworkTask; |
||||
|
import okhttp3.MultipartBody; |
||||
|
import okhttp3.OkHttpClient; |
||||
|
import okhttp3.Request; |
||||
|
import okhttp3.Response; |
||||
|
|
||||
|
public class SendShoutTask extends NetworkTask<Void> { |
||||
|
|
||||
|
public SendShoutTask(OnTaskStartedListener onTaskStartedListener, OnNetworkTaskFinishedListener<Void> onNetworkTaskFinishedListener) { |
||||
|
super(onTaskStartedListener, onNetworkTaskFinishedListener); |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
protected Response sendRequest(OkHttpClient client, String... input) throws IOException { |
||||
|
MultipartBody.Builder postBodyBuilder = new MultipartBody.Builder() |
||||
|
.setType(MultipartBody.FORM) |
||||
|
.addFormDataPart("sc", input[2]) |
||||
|
.addFormDataPart("tp-shout", input[1]) |
||||
|
.addFormDataPart("tp-shout-name", input[3]) |
||||
|
.addFormDataPart("shout_send", input[4]) |
||||
|
.addFormDataPart("tp-shout-url", input[5]); |
||||
|
|
||||
|
Request voteRequest = new Request.Builder() |
||||
|
.url(input[0]) |
||||
|
.header("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36") |
||||
|
.post(postBodyBuilder.build()) |
||||
|
.build(); |
||||
|
client.newCall(voteRequest).execute(); |
||||
|
return client.newCall(voteRequest).execute(); |
||||
|
} |
||||
|
|
||||
|
|
||||
|
|
||||
|
@Override |
||||
|
protected Void performTask(Document document, Response response) { |
||||
|
return null; |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
protected int getResultCode(Response response, Void data) { |
||||
|
return NetworkResultCodes.SUCCESSFUL; |
||||
|
} |
||||
|
} |
@ -0,0 +1,154 @@ |
|||||
|
package gr.thmmy.mthmmy.activities.shoutbox; |
||||
|
|
||||
|
import android.annotation.TargetApi; |
||||
|
import android.content.Context; |
||||
|
import android.content.Intent; |
||||
|
import android.net.Uri; |
||||
|
import android.os.Build; |
||||
|
import android.os.Bundle; |
||||
|
import android.view.LayoutInflater; |
||||
|
import android.view.View; |
||||
|
import android.view.ViewGroup; |
||||
|
import android.webkit.WebResourceRequest; |
||||
|
import android.webkit.WebView; |
||||
|
import android.webkit.WebViewClient; |
||||
|
import android.widget.TextView; |
||||
|
|
||||
|
import androidx.annotation.NonNull; |
||||
|
import gr.thmmy.mthmmy.R; |
||||
|
import gr.thmmy.mthmmy.activities.board.BoardActivity; |
||||
|
import gr.thmmy.mthmmy.activities.profile.ProfileActivity; |
||||
|
import gr.thmmy.mthmmy.activities.topic.TopicActivity; |
||||
|
import gr.thmmy.mthmmy.model.Shout; |
||||
|
import gr.thmmy.mthmmy.model.ThmmyPage; |
||||
|
import gr.thmmy.mthmmy.utils.CustomRecyclerView; |
||||
|
|
||||
|
import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK; |
||||
|
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.profile.ProfileActivity.BUNDLE_PROFILE_THUMBNAIL_URL; |
||||
|
import static gr.thmmy.mthmmy.activities.profile.ProfileActivity.BUNDLE_PROFILE_URL; |
||||
|
import static gr.thmmy.mthmmy.activities.profile.ProfileActivity.BUNDLE_PROFILE_USERNAME; |
||||
|
import static gr.thmmy.mthmmy.activities.topic.TopicActivity.BUNDLE_TOPIC_URL; |
||||
|
|
||||
|
public class ShoutAdapter extends CustomRecyclerView.Adapter<ShoutAdapter.ShoutViewHolder> { |
||||
|
private Context context; |
||||
|
private Shout[] shouts; |
||||
|
|
||||
|
public ShoutAdapter(Context context, Shout[] shouts) { |
||||
|
this.context = context; |
||||
|
this.shouts = shouts; |
||||
|
} |
||||
|
|
||||
|
public void setShouts(Shout[] shouts) { |
||||
|
this.shouts = shouts; |
||||
|
} |
||||
|
|
||||
|
@NonNull |
||||
|
@Override |
||||
|
public ShoutViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { |
||||
|
View view = LayoutInflater.from(parent.getContext()) |
||||
|
.inflate(R.layout.fragment_shoutbox_shout_row, parent, false); |
||||
|
return new ShoutViewHolder(view); |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public void onBindViewHolder(@NonNull ShoutViewHolder holder, int position) { |
||||
|
Shout currentShout = shouts[position]; |
||||
|
holder.author.setText(currentShout.getShouter()); |
||||
|
if (currentShout.isMemberOfTheMonth()) holder.author.setTextColor(context.getResources().getColor(R.color.member_of_the_month)); |
||||
|
else holder.author.setTextColor(context.getResources().getColor(R.color.accent)); |
||||
|
holder.author.setOnClickListener(view -> { |
||||
|
Intent intent = new Intent(context, ProfileActivity.class); |
||||
|
Bundle extras = new Bundle(); |
||||
|
extras.putString(BUNDLE_PROFILE_URL, shouts[holder.getAdapterPosition()].getShouterProfileURL()); |
||||
|
extras.putString(BUNDLE_PROFILE_THUMBNAIL_URL, ""); |
||||
|
extras.putString(BUNDLE_PROFILE_USERNAME, ""); |
||||
|
intent.putExtras(extras); |
||||
|
intent.setFlags(FLAG_ACTIVITY_NEW_TASK); |
||||
|
context.startActivity(intent); |
||||
|
}); |
||||
|
holder.dateTime.setText(currentShout.getDate()); |
||||
|
holder.shoutContent.setClickable(true); |
||||
|
holder.shoutContent.setWebViewClient(new LinkLauncher()); |
||||
|
holder.shoutContent.loadDataWithBaseURL("file:///android_asset/", currentShout.getShout(), |
||||
|
"text/html", "UTF-8", null); |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public int getItemCount() { |
||||
|
return shouts.length; |
||||
|
} |
||||
|
|
||||
|
static class ShoutViewHolder extends CustomRecyclerView.ViewHolder { |
||||
|
|
||||
|
TextView author, dateTime; |
||||
|
WebView shoutContent; |
||||
|
|
||||
|
ShoutViewHolder(@NonNull View itemView) { |
||||
|
super(itemView); |
||||
|
|
||||
|
author = itemView.findViewById(R.id.author_textview); |
||||
|
dateTime = itemView.findViewById(R.id.date_time_textview); |
||||
|
shoutContent = itemView.findViewById(R.id.shout_content); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
class LinkLauncher extends WebViewClient { |
||||
|
|
||||
|
@TargetApi(Build.VERSION_CODES.LOLLIPOP) |
||||
|
@Override |
||||
|
public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request) { |
||||
|
final Uri uri = request.getUrl(); |
||||
|
return handleUri(uri); |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public boolean shouldOverrideUrlLoading(WebView view, String url) { |
||||
|
final Uri uri = Uri.parse(url); |
||||
|
return handleUri(uri); |
||||
|
} |
||||
|
|
||||
|
private boolean handleUri(Uri uri) { |
||||
|
final String uriString = uri.toString(); |
||||
|
|
||||
|
ThmmyPage.PageCategory target = ThmmyPage.resolvePageCategory(uri); |
||||
|
if (target.is(ThmmyPage.PageCategory.TOPIC)) { |
||||
|
//This url points to a topic
|
||||
|
Intent intent = new Intent(context, TopicActivity.class); |
||||
|
Bundle extras = new Bundle(); |
||||
|
extras.putString(BUNDLE_TOPIC_URL, uriString); |
||||
|
intent.putExtras(extras); |
||||
|
intent.setFlags(FLAG_ACTIVITY_NEW_TASK); |
||||
|
context.startActivity(intent); |
||||
|
return true; |
||||
|
} else if (target.is(ThmmyPage.PageCategory.BOARD)) { |
||||
|
Intent intent = new Intent(context, BoardActivity.class); |
||||
|
Bundle extras = new Bundle(); |
||||
|
extras.putString(BUNDLE_BOARD_URL, uriString); |
||||
|
extras.putString(BUNDLE_BOARD_TITLE, ""); |
||||
|
intent.putExtras(extras); |
||||
|
intent.setFlags(FLAG_ACTIVITY_NEW_TASK); |
||||
|
context.startActivity(intent); |
||||
|
return true; |
||||
|
} else if (target.is(ThmmyPage.PageCategory.PROFILE)) { |
||||
|
Intent intent = new Intent(context, ProfileActivity.class); |
||||
|
Bundle extras = new Bundle(); |
||||
|
extras.putString(BUNDLE_PROFILE_URL, uriString); |
||||
|
extras.putString(BUNDLE_PROFILE_THUMBNAIL_URL, ""); |
||||
|
extras.putString(BUNDLE_PROFILE_USERNAME, ""); |
||||
|
intent.putExtras(extras); |
||||
|
intent.setFlags(FLAG_ACTIVITY_NEW_TASK); |
||||
|
context.startActivity(intent); |
||||
|
return true; |
||||
|
} |
||||
|
|
||||
|
Intent intent = new Intent(Intent.ACTION_VIEW, uri); |
||||
|
intent.setFlags(FLAG_ACTIVITY_NEW_TASK); |
||||
|
context.startActivity(intent); |
||||
|
|
||||
|
//Method always returns true as no url should be loaded in the WebViews
|
||||
|
return true; |
||||
|
} |
||||
|
} |
||||
|
} |
@ -0,0 +1,39 @@ |
|||||
|
package gr.thmmy.mthmmy.activities.shoutbox; |
||||
|
|
||||
|
import android.os.Bundle; |
||||
|
|
||||
|
import gr.thmmy.mthmmy.R; |
||||
|
import gr.thmmy.mthmmy.base.BaseActivity; |
||||
|
|
||||
|
public class ShoutboxActivity extends BaseActivity { |
||||
|
|
||||
|
@Override |
||||
|
protected void onCreate(Bundle savedInstanceState) { |
||||
|
super.onCreate(savedInstanceState); |
||||
|
setContentView(R.layout.activity_shoutbox); |
||||
|
|
||||
|
//Initialize toolbar
|
||||
|
toolbar = findViewById(R.id.toolbar); |
||||
|
toolbar.setTitle("Shoutbox"); |
||||
|
setSupportActionBar(toolbar); |
||||
|
if (getSupportActionBar() != null) { |
||||
|
getSupportActionBar().setDisplayHomeAsUpEnabled(true); |
||||
|
getSupportActionBar().setDisplayShowHomeEnabled(true); |
||||
|
} |
||||
|
|
||||
|
createDrawer(); |
||||
|
drawer.setSelection(SHOUTBOX_ID); |
||||
|
|
||||
|
if (savedInstanceState == null) { |
||||
|
getSupportFragmentManager().beginTransaction() |
||||
|
.replace(R.id.container, ShoutboxFragment.newInstance()) |
||||
|
.commitNow(); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
protected void onResume() { |
||||
|
drawer.setSelection(SHOUTBOX_ID); |
||||
|
super.onResume(); |
||||
|
} |
||||
|
} |
@ -0,0 +1,182 @@ |
|||||
|
package gr.thmmy.mthmmy.activities.shoutbox; |
||||
|
|
||||
|
import android.app.Activity; |
||||
|
import android.os.Bundle; |
||||
|
import android.view.LayoutInflater; |
||||
|
import android.view.Menu; |
||||
|
import android.view.MenuInflater; |
||||
|
import android.view.MenuItem; |
||||
|
import android.view.View; |
||||
|
import android.view.ViewGroup; |
||||
|
import android.view.inputmethod.InputConnection; |
||||
|
import android.view.inputmethod.InputMethodManager; |
||||
|
import android.widget.Toast; |
||||
|
|
||||
|
import androidx.annotation.NonNull; |
||||
|
import androidx.annotation.Nullable; |
||||
|
import androidx.fragment.app.Fragment; |
||||
|
import androidx.lifecycle.ViewModelProviders; |
||||
|
import androidx.recyclerview.widget.LinearLayoutManager; |
||||
|
import gr.thmmy.mthmmy.R; |
||||
|
import gr.thmmy.mthmmy.editorview.EditorView; |
||||
|
import gr.thmmy.mthmmy.editorview.EmojiKeyboard; |
||||
|
import gr.thmmy.mthmmy.model.Shout; |
||||
|
import gr.thmmy.mthmmy.model.Shoutbox; |
||||
|
import gr.thmmy.mthmmy.session.SessionManager; |
||||
|
import gr.thmmy.mthmmy.utils.CustomRecyclerView; |
||||
|
import gr.thmmy.mthmmy.utils.NetworkResultCodes; |
||||
|
import gr.thmmy.mthmmy.viewmodel.ShoutboxViewModel; |
||||
|
import me.zhanghai.android.materialprogressbar.MaterialProgressBar; |
||||
|
import timber.log.Timber; |
||||
|
|
||||
|
public class ShoutboxFragment extends Fragment implements EmojiKeyboard.EmojiKeyboardOwner { |
||||
|
|
||||
|
private MaterialProgressBar progressBar; |
||||
|
private ShoutboxTask shoutboxTask; |
||||
|
private ShoutAdapter shoutAdapter; |
||||
|
private EmojiKeyboard emojiKeyboard; |
||||
|
private EditorView editorView; |
||||
|
|
||||
|
private ShoutboxViewModel shoutboxViewModel; |
||||
|
|
||||
|
public static ShoutboxFragment newInstance() { |
||||
|
return new ShoutboxFragment(); |
||||
|
} |
||||
|
|
||||
|
@Nullable |
||||
|
@Override |
||||
|
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, |
||||
|
@Nullable Bundle savedInstanceState) { |
||||
|
final View rootView = inflater.inflate(R.layout.fragment_shoutbox, container, false); |
||||
|
setHasOptionsMenu(true); |
||||
|
|
||||
|
progressBar = rootView.findViewById(R.id.progressBar); |
||||
|
CustomRecyclerView recyclerView = rootView.findViewById(R.id.shoutbox_recyclerview); |
||||
|
shoutAdapter = new ShoutAdapter(getContext(), new Shout[0]); |
||||
|
recyclerView.setAdapter(shoutAdapter); |
||||
|
LinearLayoutManager layoutManager = new LinearLayoutManager(getContext()); |
||||
|
layoutManager.setReverseLayout(true); |
||||
|
recyclerView.setLayoutManager(layoutManager); |
||||
|
recyclerView.setOnTouchListener((view, motionEvent) -> { |
||||
|
editorView.hideMarkdown(); |
||||
|
InputMethodManager imm = (InputMethodManager) getContext().getSystemService(Activity.INPUT_METHOD_SERVICE); |
||||
|
imm.hideSoftInputFromWindow(editorView.getWindowToken(), 0); |
||||
|
return false; |
||||
|
}); |
||||
|
|
||||
|
emojiKeyboard = rootView.findViewById(R.id.emoji_keyboard); |
||||
|
editorView = rootView.findViewById(R.id.edior_view); |
||||
|
editorView.setEmojiKeyboardOwner(this); |
||||
|
InputConnection ic = editorView.getInputConnection(); |
||||
|
setEmojiKeyboardInputConnection(ic); |
||||
|
editorView.setOnSubmitListener(view -> { |
||||
|
if (shoutboxViewModel.getShoutboxMutableLiveData().getValue() == null) return; |
||||
|
if (editorView.getText().toString().isEmpty()) { |
||||
|
editorView.setError("Required"); |
||||
|
return; |
||||
|
} |
||||
|
shoutboxViewModel.sendShout(editorView.getText().toString()); |
||||
|
}); |
||||
|
editorView.hideMarkdown(); |
||||
|
editorView.setOnTouchListener((view, motionEvent) -> { |
||||
|
editorView.showMarkdown(); |
||||
|
return false; |
||||
|
}); |
||||
|
editorView.setMarkdownVisible(false); |
||||
|
editorView.showMarkdownOnfocus(); |
||||
|
|
||||
|
return rootView; |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { |
||||
|
inflater.inflate(R.menu.shoutbox_menu, menu); |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public boolean onOptionsItemSelected(MenuItem item) { |
||||
|
if (item.getItemId() == R.id.menu_refresh) { |
||||
|
shoutboxViewModel.loadShoutbox(); |
||||
|
return true; |
||||
|
} else { |
||||
|
return false; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public void onActivityCreated(@Nullable Bundle savedInstanceState) { |
||||
|
super.onActivityCreated(savedInstanceState); |
||||
|
shoutboxViewModel = ViewModelProviders.of(this).get(ShoutboxViewModel.class); |
||||
|
shoutboxViewModel.getShoutboxMutableLiveData().observe(this, shoutbox -> { |
||||
|
if (shoutbox != null) { |
||||
|
Timber.i("Shoutbox loaded successfully"); |
||||
|
shoutAdapter.setShouts(shoutbox.getShouts()); |
||||
|
shoutAdapter.notifyDataSetChanged(); |
||||
|
} |
||||
|
}); |
||||
|
shoutboxViewModel.setOnShoutboxTaskStarted(this::onShoutboxTaskSarted); |
||||
|
shoutboxViewModel.setOnShoutboxTaskFinished(this::onShoutboxTaskFinished); |
||||
|
shoutboxViewModel.setOnSendShoutTaskStarted(this::onSendShoutTaskStarted); |
||||
|
shoutboxViewModel.setOnSendShoutTaskFinished(this::onSendShoutTaskFinished); |
||||
|
|
||||
|
shoutboxViewModel.loadShoutbox(); |
||||
|
} |
||||
|
|
||||
|
private void onShoutboxTaskSarted() { |
||||
|
Timber.i("Starting shoutbox task..."); |
||||
|
progressBar.setVisibility(View.VISIBLE); |
||||
|
} |
||||
|
|
||||
|
private void onSendShoutTaskStarted() { |
||||
|
Timber.i("Start sending a shout..."); |
||||
|
editorView.setAlpha(0.5f); |
||||
|
editorView.setEnabled(false); |
||||
|
setEmojiKeyboardVisible(false); |
||||
|
progressBar.setVisibility(View.VISIBLE); |
||||
|
} |
||||
|
|
||||
|
private void onSendShoutTaskFinished(int resultCode, Void ignored) { |
||||
|
editorView.setAlpha(1f); |
||||
|
editorView.setEnabled(true); |
||||
|
progressBar.setVisibility(View.INVISIBLE); |
||||
|
if (resultCode == NetworkResultCodes.SUCCESSFUL) { |
||||
|
Timber.i("Shout was sent successfully"); |
||||
|
editorView.getEditText().getText().clear(); |
||||
|
shoutboxTask = new ShoutboxTask(ShoutboxFragment.this::onShoutboxTaskSarted, ShoutboxFragment.this::onShoutboxTaskFinished); |
||||
|
shoutboxTask.execute(SessionManager.shoutboxUrl.toString()); |
||||
|
} else if (resultCode == NetworkResultCodes.NETWORK_ERROR) { |
||||
|
Timber.w("Failed to send shout"); |
||||
|
Toast.makeText(getContext(), "NetworkError", Toast.LENGTH_SHORT).show(); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
private void onShoutboxTaskFinished(int resultCode, Shoutbox shoutbox) { |
||||
|
progressBar.setVisibility(View.INVISIBLE); |
||||
|
if (resultCode == NetworkResultCodes.SUCCESSFUL) { |
||||
|
shoutboxViewModel.setShoutbox(shoutbox); |
||||
|
if (shoutbox.getShoutSend() != null) |
||||
|
editorView.setVisibility(View.VISIBLE); |
||||
|
} else if (resultCode == NetworkResultCodes.NETWORK_ERROR) { |
||||
|
Timber.w("Failed to retreive shoutbox due to network error"); |
||||
|
Toast.makeText(getContext(), "NetworkError", Toast.LENGTH_SHORT).show(); |
||||
|
} else { |
||||
|
Timber.wtf("Failed to retreive shoutbox due to unknown error"); |
||||
|
Toast.makeText(getContext(), "Failed to retrieve shoutbox, please contact mthmmy developer team", Toast.LENGTH_LONG).show(); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public void setEmojiKeyboardVisible(boolean visible) { |
||||
|
emojiKeyboard.setVisibility(visible ? View.VISIBLE : View.GONE); |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public boolean isEmojiKeyboardVisible() { |
||||
|
return emojiKeyboard.getVisibility() == View.VISIBLE; |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public void setEmojiKeyboardInputConnection(InputConnection ic) { |
||||
|
emojiKeyboard.setInputConnection(ic); |
||||
|
} |
||||
|
} |
@ -0,0 +1,61 @@ |
|||||
|
package gr.thmmy.mthmmy.activities.shoutbox; |
||||
|
|
||||
|
import org.jsoup.nodes.Document; |
||||
|
import org.jsoup.nodes.Element; |
||||
|
|
||||
|
import java.util.ArrayList; |
||||
|
|
||||
|
import gr.thmmy.mthmmy.model.Shout; |
||||
|
import gr.thmmy.mthmmy.model.Shoutbox; |
||||
|
import gr.thmmy.mthmmy.utils.NetworkResultCodes; |
||||
|
import gr.thmmy.mthmmy.utils.parsing.NewParseTask; |
||||
|
import gr.thmmy.mthmmy.utils.parsing.ParseException; |
||||
|
import gr.thmmy.mthmmy.utils.parsing.ParseHelpers; |
||||
|
import okhttp3.Response; |
||||
|
|
||||
|
public class ShoutboxTask extends NewParseTask<Shoutbox> { |
||||
|
|
||||
|
public ShoutboxTask(OnTaskStartedListener onTaskStartedListener, OnNetworkTaskFinishedListener<Shoutbox> onParseTaskFinishedListener) { |
||||
|
super(onTaskStartedListener, onParseTaskFinishedListener); |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
protected Shoutbox parse(Document document, Response response) throws ParseException { |
||||
|
// fragment_shoutbox_shout_row container: document.select("div[class=smalltext]" && div.text().contains("Τελευταίες 75 φωνές:") η στα αγγλικα
|
||||
|
Element shoutboxContainer = document.select("table.windowbg").first(); |
||||
|
ArrayList<Shout> shouts = new ArrayList<>(); |
||||
|
for (Element shout : shoutboxContainer.select("div[style=margin: 4px;]")) { |
||||
|
Element user = shout.child(0); |
||||
|
Element link = user.select("a").first(); |
||||
|
String profileUrl = link.attr("href"); |
||||
|
String profileName = link.text(); |
||||
|
boolean memberOfTheMonth = link.attr("style").contains("#EA00FF"); |
||||
|
|
||||
|
Element date = shout.child(1); |
||||
|
String dateString = date.text(); |
||||
|
|
||||
|
Element content = shout.child(2); |
||||
|
content.removeAttr("style"); |
||||
|
String shoutContent = "<link rel=\"stylesheet\" type=\"text/css\" href=\"style.css\" />" + |
||||
|
ParseHelpers.youtubeEmbeddedFix(content); |
||||
|
shouts.add(new Shout(profileName, profileUrl, dateString, shoutContent, memberOfTheMonth)); |
||||
|
} |
||||
|
|
||||
|
Element shoutboxForm = document.select("form[name=tp-shoutbox]").first(); |
||||
|
String formUrl = shoutboxForm.attr("action"); |
||||
|
String sc = shoutboxForm.select("input[name=sc]").first().attr("value"); |
||||
|
String shoutName = shoutboxForm.select("input[name=tp-shout-name]").first().attr("value"); |
||||
|
// TODO: make shout send nullable and disable shouting
|
||||
|
Element shoutSendInput = shoutboxForm.select("input[name=shout_send]").first(); |
||||
|
String shoutSend = null; |
||||
|
if (shoutSendInput != null) |
||||
|
shoutSend = shoutSendInput.attr("value"); |
||||
|
String shoutUrl = shoutboxForm.select("input[name=tp-shout-url]").first().attr("value"); |
||||
|
return new Shoutbox(shouts.toArray(new Shout[0]), sc, formUrl, shoutName, shoutSend, shoutUrl); |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
protected int getResultCode(Response response, Shoutbox data) { |
||||
|
return NetworkResultCodes.SUCCESSFUL; |
||||
|
} |
||||
|
} |
@ -0,0 +1,34 @@ |
|||||
|
package gr.thmmy.mthmmy.model; |
||||
|
|
||||
|
public class Shout { |
||||
|
private final String shouter, shouterProfileURL, date, shout; |
||||
|
private final boolean memberOfTheMonth; |
||||
|
|
||||
|
public Shout(String shouter, String shouterProfileURL, String date, String shout, boolean memberOfTheMonth) { |
||||
|
this.shouter = shouter; |
||||
|
this.shouterProfileURL = shouterProfileURL; |
||||
|
this.date = date; |
||||
|
this.shout = shout; |
||||
|
this.memberOfTheMonth = memberOfTheMonth; |
||||
|
} |
||||
|
|
||||
|
public String getShouter() { |
||||
|
return shouter; |
||||
|
} |
||||
|
|
||||
|
public String getShouterProfileURL() { |
||||
|
return shouterProfileURL; |
||||
|
} |
||||
|
|
||||
|
public String getDate() { |
||||
|
return date; |
||||
|
} |
||||
|
|
||||
|
public String getShout() { |
||||
|
return shout; |
||||
|
} |
||||
|
|
||||
|
public boolean isMemberOfTheMonth() { |
||||
|
return memberOfTheMonth; |
||||
|
} |
||||
|
} |
@ -0,0 +1,42 @@ |
|||||
|
package gr.thmmy.mthmmy.model; |
||||
|
|
||||
|
import androidx.annotation.NonNull; |
||||
|
import timber.log.Timber; |
||||
|
|
||||
|
public class Shoutbox { |
||||
|
private Shout[] shouts; |
||||
|
private String sc, sendShoutUrl, shoutName, shoutSend, shoutUrl; |
||||
|
|
||||
|
public Shoutbox(Shout[] shouts, String sc, String sendShoutUrl, String shoutName, String shoutSend, String shoutUrl) { |
||||
|
this.shouts = shouts; |
||||
|
this.sc = sc; |
||||
|
this.sendShoutUrl = sendShoutUrl; |
||||
|
this.shoutName = shoutName; |
||||
|
this.shoutSend = shoutSend; |
||||
|
this.shoutUrl = shoutUrl; |
||||
|
} |
||||
|
|
||||
|
public Shout[] getShouts() { |
||||
|
return shouts; |
||||
|
} |
||||
|
|
||||
|
public String getSc() { |
||||
|
return sc; |
||||
|
} |
||||
|
|
||||
|
public String getSendShoutUrl() { |
||||
|
return sendShoutUrl; |
||||
|
} |
||||
|
|
||||
|
public String getShoutName() { |
||||
|
return shoutName; |
||||
|
} |
||||
|
|
||||
|
public String getShoutSend() { |
||||
|
return shoutSend; |
||||
|
} |
||||
|
|
||||
|
public String getShoutUrl() { |
||||
|
return shoutUrl; |
||||
|
} |
||||
|
} |
@ -0,0 +1,58 @@ |
|||||
|
package gr.thmmy.mthmmy.viewmodel; |
||||
|
|
||||
|
import android.os.AsyncTask; |
||||
|
|
||||
|
import androidx.lifecycle.MutableLiveData; |
||||
|
import androidx.lifecycle.ViewModel; |
||||
|
import gr.thmmy.mthmmy.activities.shoutbox.SendShoutTask; |
||||
|
import gr.thmmy.mthmmy.activities.shoutbox.ShoutboxTask; |
||||
|
import gr.thmmy.mthmmy.model.Shoutbox; |
||||
|
import gr.thmmy.mthmmy.session.SessionManager; |
||||
|
|
||||
|
public class ShoutboxViewModel extends ViewModel { |
||||
|
private MutableLiveData<Shoutbox> shoutboxMutableLiveData = new MutableLiveData<>(); |
||||
|
private ShoutboxTask shoutboxTask; |
||||
|
private ShoutboxTask.OnTaskStartedListener onShoutboxTaskStarted; |
||||
|
private ShoutboxTask.OnNetworkTaskFinishedListener<Shoutbox> onShoutboxTaskFinished; |
||||
|
private SendShoutTask.OnTaskStartedListener onSendShoutTaskStarted; |
||||
|
private SendShoutTask.OnNetworkTaskFinishedListener<Void> onSendShoutTaskFinished; |
||||
|
|
||||
|
public void loadShoutbox() { |
||||
|
if (shoutboxTask != null && shoutboxTask.getStatus() == AsyncTask.Status.RUNNING) |
||||
|
shoutboxTask.cancel(true); |
||||
|
shoutboxTask = new ShoutboxTask(onShoutboxTaskStarted, onShoutboxTaskFinished); |
||||
|
shoutboxTask.execute(SessionManager.shoutboxUrl.toString()); |
||||
|
} |
||||
|
|
||||
|
public void sendShout(String shout) { |
||||
|
if (shoutboxMutableLiveData.getValue() == null) throw new IllegalStateException("Shoutbox task has not finished yet!"); |
||||
|
Shoutbox shoutbox = shoutboxMutableLiveData.getValue(); |
||||
|
new SendShoutTask(onSendShoutTaskStarted, onSendShoutTaskFinished) |
||||
|
.execute(shoutbox.getSendShoutUrl(), shout, shoutbox.getSc(), |
||||
|
shoutbox.getShoutName(), shoutbox.getShoutSend(), shoutbox.getShoutUrl()); |
||||
|
} |
||||
|
|
||||
|
public void setShoutbox(Shoutbox shoutbox) { |
||||
|
shoutboxMutableLiveData.setValue(shoutbox); |
||||
|
} |
||||
|
|
||||
|
public MutableLiveData<Shoutbox> getShoutboxMutableLiveData() { |
||||
|
return shoutboxMutableLiveData; |
||||
|
} |
||||
|
|
||||
|
public void setOnSendShoutTaskFinished(SendShoutTask.OnNetworkTaskFinishedListener<Void> onSendShoutTaskFinished) { |
||||
|
this.onSendShoutTaskFinished = onSendShoutTaskFinished; |
||||
|
} |
||||
|
|
||||
|
public void setOnSendShoutTaskStarted(SendShoutTask.OnTaskStartedListener onSendShoutTaskStarted) { |
||||
|
this.onSendShoutTaskStarted = onSendShoutTaskStarted; |
||||
|
} |
||||
|
|
||||
|
public void setOnShoutboxTaskFinished(ShoutboxTask.OnNetworkTaskFinishedListener<Shoutbox> onShoutboxTaskFinished) { |
||||
|
this.onShoutboxTaskFinished = onShoutboxTaskFinished; |
||||
|
} |
||||
|
|
||||
|
public void setOnShoutboxTaskStarted(ShoutboxTask.OnTaskStartedListener onShoutboxTaskStarted) { |
||||
|
this.onShoutboxTaskStarted = onShoutboxTaskStarted; |
||||
|
} |
||||
|
} |
@ -0,0 +1,6 @@ |
|||||
|
<?xml version="1.0" encoding="utf-8"?> |
||||
|
<selector xmlns:android="http://schemas.android.com/apk/res/android"> |
||||
|
|
||||
|
<item android:color="@color/accent" android:state_selected="true" /> |
||||
|
<item android:color="@color/white" android:state_selected="false" /> |
||||
|
</selector> |
@ -0,0 +1,5 @@ |
|||||
|
<vector android:height="24dp" android:tint="#FFFFFF" |
||||
|
android:viewportHeight="24.0" android:viewportWidth="24.0" |
||||
|
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android"> |
||||
|
<path android:fillColor="#FF000000" android:pathData="M11.99,2C6.47,2 2,6.48 2,12s4.47,10 9.99,10C17.52,22 22,17.52 22,12S17.52,2 11.99,2zM12,20c-4.42,0 -8,-3.58 -8,-8s3.58,-8 8,-8 8,3.58 8,8 -3.58,8 -8,8zM12.5,7H11v6l5.25,3.15 0.75,-1.23 -4.5,-2.67z"/> |
||||
|
</vector> |
@ -0,0 +1,7 @@ |
|||||
|
<vector android:height="24dp" android:viewportHeight="297" |
||||
|
android:viewportWidth="297" android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android" |
||||
|
android:tint="#FFFFFF"> |
||||
|
<path android:fillColor="#FF000000" |
||||
|
android:pathData="M282.82,107.559h-25.792V10.025c0,-4.056 -2.443,-7.711 -6.19,-9.261c-3.745,-1.555 -8.059,-0.693 -10.925,2.177C195.46,47.434 157.039,68.643 132.635,78.6C106.33,89.333 90.261,89.635 90.159,89.637H14.18c-5.536,0 -10.023,4.488 -10.023,10.024v89.631c0,5.536 4.487,10.023 10.023,10.023h10.2l37.887,91.497c1.551,3.746 5.206,6.189 9.261,6.189h55.538c0.006,-0.001 0.012,-0.001 0.02,0c5.536,0 10.023,-4.488 10.023,-10.023c0,-1.588 -0.37,-3.09 -1.025,-4.424l-33.809,-81.646c22.4,4.443 73.884,21.285 137.641,85.1c1.917,1.921 4.483,2.939 7.094,2.939c0.055,0 0.109,0 0.164,0c5.468,-0.079 9.877,-4.536 9.877,-10.023c0,-0.214 -0.006,-0.428 -0.02,-0.639l-0.002,-96.896h25.792c5.536,0 10.023,-4.488 10.023,-10.024v-53.779C292.844,112.048 288.356,107.559 282.82,107.559zM24.204,109.683h55.932v69.584H24.204V109.683zM78.226,276.952l-31.139,-75.196h33.839l31.138,75.196H78.226zM100.183,180.201v-71.452c20.889,-3.123 72.28,-16.674 136.797,-75.301v84.121v0.015v53.779c0,0.008 0,0.017 0,0.025l0.002,84.111C172.466,196.876 121.072,183.326 100.183,180.201zM272.796,161.34h-15.768v-33.732h15.768V161.34z" |
||||
|
android:strokeColor="#ffffff" android:strokeWidth="1"/> |
||||
|
</vector> |
@ -0,0 +1,5 @@ |
|||||
|
<vector android:height="24dp" android:tint="#FFFFFF" |
||||
|
android:viewportHeight="24.0" android:viewportWidth="24.0" |
||||
|
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android"> |
||||
|
<path android:fillColor="#FF000000" android:pathData="M20,4L4,4c-1.11,0 -1.99,0.89 -1.99,2L2,18c0,1.11 0.89,2 2,2h16c1.11,0 2,-0.89 2,-2L22,6c0,-1.11 -0.89,-2 -2,-2zM8.5,15L7.3,15l-2.55,-3.5L4.75,15L3.5,15L3.5,9h1.25l2.5,3.5L7.25,9L8.5,9v6zM13.5,10.26L11,10.26v1.12h2.5v1.26L11,12.64v1.11h2.5L13.5,15h-4L9.5,9h4v1.26zM20.5,14c0,0.55 -0.45,1 -1,1h-4c-0.55,0 -1,-0.45 -1,-1L14.5,9h1.25v4.51h1.13L16.88,9.99h1.25v3.51h1.12L19.25,9h1.25v5z"/> |
||||
|
</vector> |
@ -0,0 +1,5 @@ |
|||||
|
<vector android:height="24dp" android:tint="#FFFFFF" |
||||
|
android:viewportHeight="24.0" android:viewportWidth="24.0" |
||||
|
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android"> |
||||
|
<path android:fillColor="#FF000000" android:pathData="M21,6h-2v9L6,15v2c0,0.55 0.45,1 1,1h11l4,4L22,7c0,-0.55 -0.45,-1 -1,-1zM17,12L17,3c0,-0.55 -0.45,-1 -1,-1L3,2c-0.55,0 -1,0.45 -1,1v14l4,-4h10c0.55,0 1,-0.45 1,-1z"/> |
||||
|
</vector> |
@ -0,0 +1,5 @@ |
|||||
|
<vector android:height="24dp" android:tint="#FFFFFF" |
||||
|
android:viewportHeight="24.0" android:viewportWidth="24.0" |
||||
|
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android"> |
||||
|
<path android:fillColor="#FF000000" android:pathData="M17.65,6.35C16.2,4.9 14.21,4 12,4c-4.42,0 -7.99,3.58 -7.99,8s3.57,8 7.99,8c3.73,0 6.84,-2.55 7.73,-6h-2.08c-0.82,2.33 -3.04,4 -5.65,4 -3.31,0 -6,-2.69 -6,-6s2.69,-6 6,-6c1.66,0 3.14,0.69 4.22,1.78L13,11h7V4l-2.35,2.35z"/> |
||||
|
</vector> |
@ -0,0 +1,31 @@ |
|||||
|
<?xml version="1.0" encoding="utf-8"?> |
||||
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" |
||||
|
xmlns:tools="http://schemas.android.com/tools" |
||||
|
android:layout_width="match_parent" |
||||
|
android:layout_height="match_parent" |
||||
|
xmlns:app="http://schemas.android.com/apk/res-auto" |
||||
|
android:orientation="vertical"> |
||||
|
|
||||
|
<com.google.android.material.appbar.AppBarLayout |
||||
|
android:id="@+id/appbar" |
||||
|
android:layout_width="match_parent" |
||||
|
android:layout_height="wrap_content" |
||||
|
android:theme="@style/ToolbarTheme"> |
||||
|
|
||||
|
<androidx.appcompat.widget.Toolbar |
||||
|
android:id="@+id/toolbar" |
||||
|
android:layout_width="match_parent" |
||||
|
android:layout_height="wrap_content" |
||||
|
android:background="?attr/colorPrimary" |
||||
|
android:gravity="center" |
||||
|
app:popupTheme="@style/ToolbarTheme" /> |
||||
|
</com.google.android.material.appbar.AppBarLayout> |
||||
|
|
||||
|
<FrameLayout |
||||
|
android:id="@+id/container" |
||||
|
android:layout_width="match_parent" |
||||
|
android:layout_height="match_parent" |
||||
|
tools:context=".ShoutboxActivity" /> |
||||
|
|
||||
|
</LinearLayout> |
||||
|
|
@ -1,5 +1,5 @@ |
|||||
<?xml version="1.0" encoding="utf-8"?> |
<?xml version="1.0" encoding="utf-8"?> |
||||
<android.support.v7.widget.AppCompatImageButton |
<androidx.appcompat.widget.AppCompatImageButton |
||||
xmlns:android="http://schemas.android.com/apk/res/android" |
xmlns:android="http://schemas.android.com/apk/res/android" |
||||
android:layout_height="wrap_content" |
android:layout_height="wrap_content" |
||||
android:layout_width="match_parent" |
android:layout_width="match_parent" |
||||
|
@ -0,0 +1,40 @@ |
|||||
|
<?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" |
||||
|
xmlns:tools="http://schemas.android.com/tools" |
||||
|
android:layout_width="match_parent" |
||||
|
android:layout_height="match_parent" |
||||
|
android:orientation="vertical"> |
||||
|
|
||||
|
<me.zhanghai.android.materialprogressbar.MaterialProgressBar |
||||
|
android:id="@+id/progressBar" |
||||
|
style="@style/Widget.MaterialProgressBar.ProgressBar.Horizontal.NoPadding" |
||||
|
android:layout_width="match_parent" |
||||
|
android:layout_height="@dimen/progress_bar_height" |
||||
|
android:indeterminate="true" |
||||
|
android:visibility="invisible" |
||||
|
app:mpb_indeterminateTint="@color/accent" |
||||
|
app:mpb_progressStyle="horizontal" /> |
||||
|
|
||||
|
<gr.thmmy.mthmmy.utils.CustomRecyclerView |
||||
|
android:id="@+id/shoutbox_recyclerview" |
||||
|
android:layout_width="match_parent" |
||||
|
android:layout_height="0dp" |
||||
|
android:layout_weight="1" |
||||
|
tools:listitem="@layout/fragment_shoutbox_shout_row" /> |
||||
|
|
||||
|
<gr.thmmy.mthmmy.editorview.EditorView |
||||
|
android:id="@+id/edior_view" |
||||
|
android:layout_width="match_parent" |
||||
|
android:layout_height="wrap_content" |
||||
|
android:layout_marginStart="8dp" |
||||
|
android:layout_marginEnd="8dp" |
||||
|
android:paddingTop="8dp" |
||||
|
android:visibility="gone"/> |
||||
|
|
||||
|
<gr.thmmy.mthmmy.editorview.EmojiKeyboard |
||||
|
android:id="@+id/emoji_keyboard" |
||||
|
android:layout_width="match_parent" |
||||
|
android:layout_height="180dp" |
||||
|
android:visibility="gone" /> |
||||
|
</LinearLayout> |
@ -0,0 +1,72 @@ |
|||||
|
<?xml version="1.0" encoding="utf-8"?> |
||||
|
<androidx.cardview.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android" |
||||
|
xmlns:card_view="http://schemas.android.com/apk/res-auto" |
||||
|
xmlns:tools="http://schemas.android.com/tools" |
||||
|
android:layout_width="match_parent" |
||||
|
android:layout_height="wrap_content" |
||||
|
android:layout_marginStart="8dp" |
||||
|
android:layout_marginEnd="8dp" |
||||
|
android:foreground="?android:attr/selectableItemBackground" |
||||
|
android:orientation="vertical" |
||||
|
card_view:cardBackgroundColor="@color/card_background" |
||||
|
card_view:cardCornerRadius="5dp" |
||||
|
card_view:cardElevation="2dp" |
||||
|
card_view:cardPreventCornerOverlap="false" |
||||
|
card_view:cardUseCompatPadding="true"> |
||||
|
|
||||
|
<LinearLayout |
||||
|
android:layout_width="match_parent" |
||||
|
android:layout_height="wrap_content" |
||||
|
android:orientation="vertical"> |
||||
|
|
||||
|
<TextView |
||||
|
android:id="@+id/author_textview" |
||||
|
android:layout_width="wrap_content" |
||||
|
android:layout_height="wrap_content" |
||||
|
android:layout_marginStart="16dp" |
||||
|
android:ellipsize="end" |
||||
|
android:maxLines="1" |
||||
|
android:paddingTop="9dp" |
||||
|
android:textColor="@color/accent" |
||||
|
android:textStyle="bold" |
||||
|
tools:text="author" /> |
||||
|
|
||||
|
<TextView |
||||
|
android:id="@+id/date_time_textview" |
||||
|
android:layout_width="wrap_content" |
||||
|
android:layout_height="wrap_content" |
||||
|
android:layout_marginStart="16dp" |
||||
|
android:textColor="@color/primary_text" |
||||
|
android:textSize="11sp" |
||||
|
tools:text="date & time" /> |
||||
|
|
||||
|
<View |
||||
|
android:id="@+id/header_body_divider" |
||||
|
android:layout_width="match_parent" |
||||
|
android:layout_height="1dp" |
||||
|
android:layout_marginLeft="16dp" |
||||
|
android:layout_marginTop="5dp" |
||||
|
android:layout_marginRight="16dp" |
||||
|
android:layout_marginBottom="9dp" |
||||
|
android:background="@color/divider" /> |
||||
|
|
||||
|
<WebView |
||||
|
android:id="@+id/shout_content" |
||||
|
android:layout_width="match_parent" |
||||
|
android:layout_height="wrap_content" |
||||
|
android:layout_gravity="center" |
||||
|
android:layout_marginLeft="16dp" |
||||
|
android:layout_marginRight="16dp" |
||||
|
android:background="@color/card_background" |
||||
|
android:clickable="true" |
||||
|
android:focusable="true" |
||||
|
android:scrollbars="none" |
||||
|
android:text="@string/post" |
||||
|
tools:ignore="WebViewLayout" /> |
||||
|
|
||||
|
<View |
||||
|
android:layout_width="match_parent" |
||||
|
android:layout_height="9dp" /> |
||||
|
</LinearLayout> |
||||
|
|
||||
|
</androidx.cardview.widget.CardView> |
@ -0,0 +1,10 @@ |
|||||
|
<?xml version="1.0" encoding="utf-8"?> |
||||
|
<menu xmlns:android="http://schemas.android.com/apk/res/android" |
||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"> |
||||
|
<item |
||||
|
android:id="@+id/menu_refresh" |
||||
|
android:icon="@drawable/ic_refresh_white_24dp" |
||||
|
app:showAsAction="ifRoom" |
||||
|
android:title="@string/refresh"> |
||||
|
</item> |
||||
|
</menu> |
Some files were not shown because too many files changed in this diff
Loading…
Reference in new issue