mirror of https://github.com/ThmmyNoLife/mTHMMY
Ezerous
6 years ago
133 changed files with 3290 additions and 1331 deletions
@ -0,0 +1,51 @@ |
|||
import org.ajoberstar.grgit.Grgit |
|||
|
|||
buildscript { |
|||
repositories { |
|||
jcenter() |
|||
} |
|||
|
|||
dependencies { |
|||
classpath 'org.ajoberstar.grgit:grgit-core:3.0.0' |
|||
} |
|||
} |
|||
|
|||
static def getCurrentBranch() { |
|||
try { |
|||
def grgit = Grgit.open() |
|||
def currentBranch = grgit.branch.getCurrent().name |
|||
grgit.close() |
|||
return currentBranch |
|||
} catch (Exception ignored) { |
|||
return "" |
|||
} |
|||
} |
|||
|
|||
static def getCommitHash() { |
|||
try { |
|||
def grgit = Grgit.open() |
|||
def commitHash = grgit.head().id |
|||
grgit.close() |
|||
return commitHash |
|||
} catch (Exception ignored) { |
|||
return "" |
|||
} |
|||
} |
|||
|
|||
//Will return true if there are no uncommitted changes |
|||
static def isClean() { |
|||
try { |
|||
def grgit = Grgit.open() |
|||
def isClean = grgit.status().isClean() |
|||
grgit.close() |
|||
return isClean |
|||
} catch (Exception ignored) { |
|||
return true |
|||
} |
|||
} |
|||
|
|||
ext { |
|||
getCurrentBranch = this.&getCurrentBranch |
|||
getCommitHash = this.&getCommitHash |
|||
isClean = this.&isClean |
|||
} |
@ -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,155 @@ |
|||
package gr.thmmy.mthmmy.activities.shoutbox; |
|||
|
|||
import android.annotation.TargetApi; |
|||
import android.content.Context; |
|||
import android.content.Intent; |
|||
import android.graphics.Color; |
|||
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; |
|||
|
|||
ShoutAdapter(Context context, Shout[] shouts) { |
|||
this.context = context; |
|||
this.shouts = shouts; |
|||
} |
|||
|
|||
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); |
|||
shoutContent.setBackgroundColor(Color.argb(1, 255, 255, 255)); |
|||
} |
|||
} |
|||
|
|||
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,54 @@ |
|||
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 { |
|||
|
|||
private ShoutboxFragment shoutboxFragment; |
|||
|
|||
@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) { |
|||
shoutboxFragment = ShoutboxFragment.newInstance(); |
|||
getSupportFragmentManager().beginTransaction() |
|||
.replace(R.id.container, shoutboxFragment) |
|||
.commitNow(); |
|||
} |
|||
} |
|||
|
|||
@Override |
|||
protected void onResume() { |
|||
drawer.setSelection(SHOUTBOX_ID); |
|||
super.onResume(); |
|||
} |
|||
|
|||
@Override |
|||
public void onBackPressed() { |
|||
int count = getSupportFragmentManager().getBackStackEntryCount(); |
|||
|
|||
if (count == 0) { |
|||
if (!shoutboxFragment.onBackPressed()) |
|||
super.onBackPressed(); |
|||
} else { |
|||
getSupportFragmentManager().popBackStack(); |
|||
} |
|||
} |
|||
} |
@ -0,0 +1,173 @@ |
|||
package gr.thmmy.mthmmy.activities.shoutbox; |
|||
|
|||
import android.app.Activity; |
|||
import android.os.AsyncTask; |
|||
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.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 { |
|||
|
|||
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.setEmojiKeyboard(emojiKeyboard); |
|||
emojiKeyboard.registerEmojiInputField(editorView); |
|||
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.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); |
|||
if (emojiKeyboard.isVisible()) |
|||
emojiKeyboard.setVisibility(View.GONE); |
|||
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(); |
|||
} |
|||
} |
|||
|
|||
/** |
|||
* @return whether or not {@link ShoutboxFragment#onBackPressed()} consumed the event or not |
|||
*/ |
|||
public boolean onBackPressed() { |
|||
if (emojiKeyboard.isVisible()) { |
|||
emojiKeyboard.setVisibility(View.GONE); |
|||
return true; |
|||
} |
|||
return false; |
|||
} |
|||
} |
@ -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,53 @@ |
|||
package gr.thmmy.mthmmy.model; |
|||
|
|||
import androidx.annotation.NonNull; |
|||
|
|||
public class BBTag { |
|||
private int start, end; |
|||
private String name, attribute; |
|||
|
|||
public BBTag(int start, String name) { |
|||
this.start = start; |
|||
this.name = name; |
|||
} |
|||
|
|||
public BBTag(int start, String name, String attribute) { |
|||
this.start = start; |
|||
this.name = name; |
|||
this.attribute = attribute; |
|||
} |
|||
|
|||
@NonNull |
|||
@Override |
|||
public String toString() { |
|||
return "start:" + start + ",end:" + end + ",name:" + name; |
|||
} |
|||
|
|||
public int getStart() { |
|||
return start; |
|||
} |
|||
|
|||
public void setStart(int start) { |
|||
this.start = start; |
|||
} |
|||
|
|||
public int getEnd() { |
|||
return end; |
|||
} |
|||
|
|||
public void setEnd(int end) { |
|||
this.end = end; |
|||
} |
|||
|
|||
public String getName() { |
|||
return name; |
|||
} |
|||
|
|||
public void setName(String name) { |
|||
this.name = name; |
|||
} |
|||
|
|||
public String getAttribute() { |
|||
return attribute; |
|||
} |
|||
} |
@ -0,0 +1,58 @@ |
|||
package gr.thmmy.mthmmy.model; |
|||
|
|||
import androidx.annotation.NonNull; |
|||
|
|||
public class HtmlTag { |
|||
private int start, end; |
|||
private String name, attributeKey, attributeValue; |
|||
|
|||
public HtmlTag(int start, String name) { |
|||
this.start = start; |
|||
this.name = name; |
|||
} |
|||
|
|||
public HtmlTag(int start, String name, String attributeKey, String attributeValue) { |
|||
this.start = start; |
|||
this.name = name; |
|||
this.attributeKey = attributeKey; |
|||
this.attributeValue = attributeValue; |
|||
} |
|||
|
|||
@NonNull |
|||
@Override |
|||
public String toString() { |
|||
return "start:" + start + ",end:" + end + ",name:" + name; |
|||
} |
|||
|
|||
public int getStart() { |
|||
return start; |
|||
} |
|||
|
|||
public void setStart(int start) { |
|||
this.start = start; |
|||
} |
|||
|
|||
public int getEnd() { |
|||
return end; |
|||
} |
|||
|
|||
public void setEnd(int end) { |
|||
this.end = end; |
|||
} |
|||
|
|||
public String getName() { |
|||
return name; |
|||
} |
|||
|
|||
public void setName(String name) { |
|||
this.name = name; |
|||
} |
|||
|
|||
public String getAttributeKey() { |
|||
return attributeKey; |
|||
} |
|||
|
|||
public String getAttributeValue() { |
|||
return attributeValue; |
|||
} |
|||
} |
@ -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,39 @@ |
|||
package gr.thmmy.mthmmy.model; |
|||
|
|||
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,221 @@ |
|||
package gr.thmmy.mthmmy.utils.parsing; |
|||
|
|||
import android.content.Context; |
|||
import android.graphics.Typeface; |
|||
import android.text.Spannable; |
|||
import android.text.SpannableStringBuilder; |
|||
import android.text.TextUtils; |
|||
import android.text.style.StrikethroughSpan; |
|||
import android.text.style.StyleSpan; |
|||
import android.text.style.URLSpan; |
|||
import android.text.style.UnderlineSpan; |
|||
|
|||
import java.nio.charset.UnsupportedCharsetException; |
|||
import java.util.LinkedList; |
|||
import java.util.regex.Matcher; |
|||
import java.util.regex.Pattern; |
|||
|
|||
import gr.thmmy.mthmmy.model.BBTag; |
|||
import gr.thmmy.mthmmy.model.HtmlTag; |
|||
import gr.thmmy.mthmmy.utils.HTMLUtils; |
|||
|
|||
public class ThmmyParser { |
|||
private static final String[] ALL_BB_TAGS = {"b", "i", "u", "s", "glow", "shadow", "move", "pre", "lefter", |
|||
"center", "right", "hr", "size", "font", "color", "youtube", "flash", "img", "url" |
|||
, "email", "ftp", "table", "tr", "td", "sup", "sub", "tt", "code", "quote", "tex", "list", "li"}; |
|||
private static final String[] ALL_HTML_TAGS = {"b", "br", "span", "i", "div", "del", "marquee", "pre", |
|||
"hr", "embed", "noembed", "a", "img", "table", "tr", "td", "sup", "sub", "tt", "pre", "ul", "li"}; |
|||
|
|||
public static SpannableStringBuilder bb2span(String bb) { |
|||
SpannableStringBuilder builder = new SpannableStringBuilder(bb); |
|||
// store the original indices of the string
|
|||
LinkedList<Integer> stringIndices = new LinkedList<>(); |
|||
for (int i = 0; i < builder.length(); i++) { |
|||
stringIndices.add(i); |
|||
} |
|||
|
|||
BBTag[] tags = getBBTags(bb); |
|||
for (BBTag tag : tags) { |
|||
int start = stringIndices.indexOf(tag.getStart()); |
|||
int end = stringIndices.indexOf(tag.getEnd()); |
|||
int startTagLength = tag.getName().length() + 2; |
|||
int endTagLength = tag.getName().length() + 3; |
|||
switch (tag.getName()) { |
|||
case "b": |
|||
builder.setSpan(new StyleSpan(Typeface.BOLD), start, end, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); |
|||
break; |
|||
case "i": |
|||
builder.setSpan(new StyleSpan(Typeface.ITALIC), start, end, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); |
|||
break; |
|||
case "u": |
|||
builder.setSpan(new UnderlineSpan(), start, end, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); |
|||
break; |
|||
case "s": |
|||
builder.setSpan(new StrikethroughSpan(), start, end, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); |
|||
break; |
|||
default: |
|||
throw new UnsupportedCharsetException("Tag not supported"); |
|||
} |
|||
//remove starting and ending tag and and do the same changes in the list
|
|||
builder.delete(start, start + startTagLength); |
|||
for (int i = start; i < start + startTagLength; i++) { |
|||
stringIndices.remove(start); |
|||
} |
|||
builder.delete(end - startTagLength, end - startTagLength + endTagLength); |
|||
for (int i = end - startTagLength; i < end - startTagLength + endTagLength; i++) { |
|||
stringIndices.remove(end - startTagLength); |
|||
} |
|||
} |
|||
return builder; |
|||
} |
|||
|
|||
public static SpannableStringBuilder html2span(Context context, String html) { |
|||
SpannableStringBuilder builder = new SpannableStringBuilder(html); |
|||
// store the original indices of the string
|
|||
LinkedList<Integer> stringIndices = new LinkedList<>(); |
|||
for (int i = 0; i < builder.length(); i++) { |
|||
stringIndices.add(i); |
|||
} |
|||
|
|||
HtmlTag[] tags = getHtmlTags(html); |
|||
for (HtmlTag tag : tags) { |
|||
int start = stringIndices.indexOf(tag.getStart()); |
|||
int end = stringIndices.indexOf(tag.getEnd()); |
|||
int startTagLength = tag.getName().length() + 2; |
|||
if (tag.getAttributeKey() != null) { |
|||
startTagLength += tag.getAttributeKey().length() + tag.getAttributeValue().length() + 4; |
|||
} |
|||
int endTagLength = tag.getName().length() + 3; |
|||
|
|||
if (isHtmlTagSupported(tag.getName(), tag.getAttributeKey(), tag.getAttributeValue())) { |
|||
switch (tag.getName()) { |
|||
case "b": |
|||
builder.setSpan(new StyleSpan(Typeface.BOLD), start, end, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); |
|||
break; |
|||
case "i": |
|||
builder.setSpan(new StyleSpan(Typeface.ITALIC), start, end, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); |
|||
break; |
|||
case "span": |
|||
if (tag.getAttributeKey().equals("style") && tag.getAttributeValue().equals("text-decoration: underline;")) { |
|||
builder.setSpan(new UnderlineSpan(), start, end, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); |
|||
} |
|||
break; |
|||
case "del": |
|||
builder.setSpan(new StrikethroughSpan(), start, end, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); |
|||
break; |
|||
case "a": |
|||
URLSpan urlSpan = new URLSpan(tag.getAttributeValue()); |
|||
builder.setSpan(urlSpan, start, end, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); |
|||
HTMLUtils.makeLinkClickable(context, builder, urlSpan); |
|||
break; |
|||
default: |
|||
throw new UnsupportedCharsetException("Tag not supported"); |
|||
} |
|||
} |
|||
|
|||
//remove starting and ending tag and and do the same changes in the list
|
|||
builder.delete(start, start + startTagLength); |
|||
for (int i = start; i < start + startTagLength; i++) { |
|||
stringIndices.remove(start); |
|||
} |
|||
builder.delete(end - startTagLength, end - startTagLength + endTagLength); |
|||
for (int i = end - startTagLength; i < end - startTagLength + endTagLength; i++) { |
|||
stringIndices.remove(end - startTagLength); |
|||
} |
|||
} |
|||
return builder; |
|||
} |
|||
|
|||
public static BBTag[] getBBTags(String bb) { |
|||
Pattern bbtagPattern = Pattern.compile("\\[(.+?)\\]"); |
|||
|
|||
LinkedList<BBTag> tags = new LinkedList<>(); |
|||
Matcher bbMatcher = bbtagPattern.matcher(bb); |
|||
while (bbMatcher.find()) { |
|||
String startTag = bbMatcher.group(1); |
|||
int separatorIndex = startTag.indexOf('='); |
|||
String name, attribute = null; |
|||
if (separatorIndex > 0) { |
|||
attribute = startTag.substring(separatorIndex); |
|||
name = startTag.substring(0, separatorIndex); |
|||
} else |
|||
name = startTag; |
|||
|
|||
if (name.startsWith("/")) { |
|||
//closing tag
|
|||
name = name.substring(1); |
|||
for (int i = tags.size() - 1; i >= 0; i--) { |
|||
if (tags.get(i).getName().equals(name)) { |
|||
tags.get(i).setEnd(bbMatcher.start()); |
|||
break; |
|||
} |
|||
} |
|||
continue; |
|||
} |
|||
if (isBBTagSupported(name)) |
|||
tags.add(new BBTag(bbMatcher.start(), name, attribute)); |
|||
} |
|||
// remove parsed tags with no end tag
|
|||
for (BBTag bbTag : tags) |
|||
if (bbTag.getEnd() == 0) |
|||
tags.remove(bbTag); |
|||
return tags.toArray(new BBTag[0]); |
|||
} |
|||
|
|||
private static HtmlTag[] getHtmlTags(String html) { |
|||
Pattern htmlPattern = Pattern.compile("<(.+?)>"); |
|||
|
|||
LinkedList<HtmlTag> tags = new LinkedList<>(); |
|||
Matcher htmlMatcher = htmlPattern.matcher(html); |
|||
while (htmlMatcher.find()) { |
|||
String startTag = htmlMatcher.group(1); |
|||
int separatorIndex = startTag.indexOf(' '); |
|||
String name, attribute = null, attributeValue = null; |
|||
if (separatorIndex > 0) { |
|||
String fullAttribute = startTag.substring(separatorIndex); |
|||
int equalsIndex = fullAttribute.indexOf('='); |
|||
attribute = fullAttribute.substring(1, equalsIndex); |
|||
attributeValue = fullAttribute.substring(equalsIndex + 2, fullAttribute.length() - 1); |
|||
name = startTag.substring(0, separatorIndex); |
|||
} else |
|||
name = startTag; |
|||
|
|||
if (name.startsWith("/")) { |
|||
//closing tag
|
|||
name = name.substring(1); |
|||
for (int i = tags.size() - 1; i >= 0; i--) { |
|||
if (tags.get(i).getName().equals(name)) { |
|||
tags.get(i).setEnd(htmlMatcher.start()); |
|||
break; |
|||
} |
|||
} |
|||
continue; |
|||
} |
|||
if (isHtmlTag(name)) |
|||
tags.add(new HtmlTag(htmlMatcher.start(), name, attribute, attributeValue)); |
|||
} |
|||
// remove parsed tags with no end tag
|
|||
for (HtmlTag htmlTag : tags) |
|||
if (htmlTag.getEnd() == 0) |
|||
tags.remove(htmlTag); |
|||
return tags.toArray(new HtmlTag[0]); |
|||
} |
|||
|
|||
private static boolean isHtmlTagSupported(String name, String attribute, String attributeValue) { |
|||
return name.equals("b") || name.equals("i") || name.equals("span") || name.equals("del") || name.equals("a"); |
|||
} |
|||
|
|||
private static boolean isBBTagSupported(String name) { |
|||
return name.equals("b") || name.equals("i") || name.equals("u") || name.equals("s"); |
|||
} |
|||
|
|||
private static boolean isHtmlTag(String tagName) { |
|||
for (String tag : ALL_HTML_TAGS) |
|||
if (TextUtils.equals(tag, tagName)) return true; |
|||
return false; |
|||
} |
|||
|
|||
public static boolean containsHtml(String s) { |
|||
return getHtmlTags(s).length > 0; |
|||
} |
|||
} |
@ -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="#000000" android:strokeWidth="1"/> |
|||
</vector> |
@ -1,5 +1,5 @@ |
|||
<vector android:height="24dp" android:tint="@color/accent" |
|||
<vector android:height="48dp" android:tint="@color/accent" |
|||
android:viewportHeight="24.0" android:viewportWidth="24.0" |
|||
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android"> |
|||
android:width="30dp" xmlns:android="http://schemas.android.com/apk/res/android"> |
|||
<path android:fillColor="#FF000000" android:pathData="M7,10l5,5 5,-5z"/> |
|||
</vector> |
|||
|
@ -1,5 +1,5 @@ |
|||
<vector android:height="24dp" android:tint="@color/accent" |
|||
<vector android:height="48dp" android:tint="@color/accent" |
|||
android:viewportHeight="24.0" android:viewportWidth="24.0" |
|||
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android"> |
|||
android:width="30dp" xmlns:android="http://schemas.android.com/apk/res/android"> |
|||
<path android:fillColor="#FF000000" android:pathData="M7,14l5,-5 5,5z"/> |
|||
</vector> |
|||
|
@ -0,0 +1,5 @@ |
|||
<vector android:height="24dp" android:viewportHeight="512" |
|||
android:viewportWidth="512" android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android"> |
|||
<path android:fillColor="#ffffff" android:pathData="M256,60c-108.27,0 -196,87.73 -196,196c0,108.27 87.73,196 196,196c108.27,0 196,-87.73 196,-196c0,-108.27 -87.73,-196 -196,-196z"/> |
|||
<path android:fillColor="#3c3c3c" android:pathData="M504,256c0,137 -111,248 -248,248c-137,0 -248,-111 -248,-248c0,-137 111,-248 248,-248c137,0 248,111 248,248zM168,192c0,48.6 39.4,88 88,88c48.6,0 88,-39.4 88,-88c0,-48.6 -39.4,-88 -88,-88c-48.6,0 -88,39.4 -88,88zM402.5,379.8c-18.8,-35.4 -55.6,-59.8 -98.5,-59.8c-2.4,0 -4.8,0.4 -7.1,1.1c-12.9,4.2 -26.6,6.9 -40.9,6.9c-14.3,0 -27.9,-2.7 -40.9,-6.9c-2.3,-0.7 -4.7,-1.1 -7.1,-1.1c-42.9,0 -79.7,24.4 -98.5,59.8c35.2,41.6 87.8,68.2 146.5,68.2c58.7,0 111.3,-26.6 146.5,-68.2z"/> |
|||
</vector> |
@ -0,0 +1,5 @@ |
|||
<vector android:height="24dp" android:viewportHeight="512" |
|||
android:viewportWidth="512" android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android"> |
|||
<path android:fillColor="#ffffff" android:pathData="M256,60c-108.27,0 -196,87.73 -196,196c0,108.27 87.73,196 196,196c108.27,0 196,-87.73 196,-196c0,-108.27 -87.73,-196 -196,-196z"/> |
|||
<path android:fillColor="#323232" android:pathData="M504,256c0,137 -111,248 -248,248c-137,0 -248,-111 -248,-248c0,-137 111,-248 248,-248c137,0 248,111 248,248zM168,192c0,48.6 39.4,88 88,88c48.6,0 88,-39.4 88,-88c0,-48.6 -39.4,-88 -88,-88c-48.6,0 -88,39.4 -88,88zM402.5,379.8c-18.8,-35.4 -55.6,-59.8 -98.5,-59.8c-2.4,0 -4.8,0.4 -7.1,1.1c-12.9,4.2 -26.6,6.9 -40.9,6.9c-14.3,0 -27.9,-2.7 -40.9,-6.9c-2.3,-0.7 -4.7,-1.1 -7.1,-1.1c-42.9,0 -79.7,24.4 -98.5,59.8c35.2,41.6 87.8,68.2 146.5,68.2c58.7,0 111.3,-26.6 146.5,-68.2z"/> |
|||
</vector> |
@ -1,5 +0,0 @@ |
|||
<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="M12,12c2.21,0 4,-1.79 4,-4s-1.79,-4 -4,-4 -4,1.79 -4,4 1.79,4 4,4zM12,14c-2.67,0 -8,1.34 -8,4v2h16v-2c0,-2.66 -5.33,-4 -8,-4z"/> |
|||
</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> |
Some files were not shown because too many files changed in this diff
Loading…
Reference in new issue