Skip to content
Snippets Groups Projects
Commit 782f0bf6 authored by John Carlson's avatar John Carlson
Browse files

Activities to Kotlin

parent b1c6eb36
No related branches found
No related tags found
No related merge requests found
Showing
with 1530 additions and 1702 deletions
Loading
Loading
@@ -130,7 +130,7 @@ class AboutActivity : BaseActivity() {
sensorManager.unregisterListener(sensorEventListener)
}
 
private fun addContributors(contributors: List<Contributor>) {
fun addContributors(contributors: List<Contributor>) {
val config = PhysicsConfig.create()
config.shapeType = PhysicsConfig.SHAPE_TYPE_CIRCLE
val borderSize = resources.getDimensionPixelSize(R.dimen.border_size)
Loading
Loading
Loading
Loading
@@ -45,6 +45,22 @@ import java.util.*
*/
class AddIssueActivity : MorphActivity() {
 
companion object {
private val REQUEST_LABEL = 1
private val KEY_PROJECT = "project"
private val KEY_ISSUE = "issue"
fun newIntent(context: Context, project: Project, issue: Issue?): Intent {
val intent = Intent(context, AddIssueActivity::class.java)
intent.putExtra(KEY_PROJECT, Parcels.wrap(project))
if (issue != null) {
intent.putExtra(KEY_ISSUE, Parcels.wrap(issue))
}
return intent
}
}
@BindView(R.id.root)
lateinit var root: FrameLayout
@BindView(R.id.toolbar)
Loading
Loading
@@ -80,7 +96,7 @@ class AddIssueActivity : MorphActivity() {
lateinit var members: HashSet<Member>
 
@OnClick(R.id.text_add_labels)
internal fun onAddLabelClicked() {
fun onAddLabelClicked() {
Navigator.navigateToAddLabels(this, project, REQUEST_LABEL)
}
 
Loading
Loading
@@ -338,7 +354,7 @@ class AddIssueActivity : MorphActivity() {
 
override fun error(t: Throwable) {
Timber.e(t)
Snackbar.make(root!!, getString(R.string.failed_to_create_issue), Snackbar.LENGTH_SHORT)
Snackbar.make(root, getString(R.string.failed_to_create_issue), Snackbar.LENGTH_SHORT)
.show()
}
 
Loading
Loading
@@ -352,21 +368,4 @@ class AddIssueActivity : MorphActivity() {
}
})
}
companion object {
private val REQUEST_LABEL = 1
private val KEY_PROJECT = "project"
private val KEY_ISSUE = "issue"
fun newIntent(context: Context, project: Project, issue: Issue?): Intent {
val intent = Intent(context, AddIssueActivity::class.java)
intent.putExtra(KEY_PROJECT, Parcels.wrap(project))
if (issue != null) {
intent.putExtra(KEY_ISSUE, Parcels.wrap(issue))
}
return intent
}
}
}
\ No newline at end of file
package com.commit451.gitlab.activity;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.v4.widget.SwipeRefreshLayout;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.Toolbar;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import com.commit451.gitlab.App;
import com.commit451.gitlab.R;
import com.commit451.gitlab.adapter.LabelAdapter;
import com.commit451.gitlab.model.api.Label;
import com.commit451.gitlab.navigation.Navigator;
import com.commit451.gitlab.rx.CustomSingleObserver;
import com.commit451.gitlab.viewHolder.LabelViewHolder;
import org.parceler.Parcels;
import java.util.List;
import butterknife.BindView;
import butterknife.ButterKnife;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.schedulers.Schedulers;
import timber.log.Timber;
import static com.commit451.gitlab.R.string.labels;
/**
* Add labels!
*/
public class AddLabelActivity extends BaseActivity {
private static final String KEY_PROJECT_ID = "project_id";
private static final int REQUEST_NEW_LABEL = 1;
public static final String KEY_LABEL = "label";
public static Intent newIntent(Context context, long projectId) {
Intent intent = new Intent(context, AddLabelActivity.class);
intent.putExtra(KEY_PROJECT_ID, projectId);
return intent;
}
@BindView(R.id.root)
ViewGroup root;
@BindView(R.id.toolbar)
Toolbar toolbar;
@BindView(R.id.swipe_layout)
SwipeRefreshLayout swipeRefreshLayout;
@BindView(R.id.list)
RecyclerView list;
LabelAdapter adapterLabel;
@BindView(R.id.message_text)
TextView textMessage;
long projectId;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_add_label);
ButterKnife.bind(this);
projectId = getIntent().getLongExtra(KEY_PROJECT_ID, -1);
toolbar.setTitle(labels);
toolbar.inflateMenu(R.menu.menu_add_label);
toolbar.setOnMenuItemClickListener(new Toolbar.OnMenuItemClickListener() {
@Override
public boolean onMenuItemClick(MenuItem item) {
switch (item.getItemId()) {
case R.id.action_add_label:
Navigator.navigateToAddNewLabel(AddLabelActivity.this, projectId, REQUEST_NEW_LABEL);
return true;
}
return false;
}
});
swipeRefreshLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
@Override
public void onRefresh() {
load();
}
});
adapterLabel = new LabelAdapter(new LabelAdapter.Listener() {
@Override
public void onLabelClicked(Label label, LabelViewHolder viewHolder) {
Intent data = new Intent();
data.putExtra(KEY_LABEL, Parcels.wrap(label));
setResult(RESULT_OK, data);
finish();
}
});
list.setAdapter(adapterLabel);
list.setLayoutManager(new LinearLayoutManager(this));
toolbar.setNavigationIcon(R.drawable.ic_back_24dp);
toolbar.setNavigationOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
onBackPressed();
}
});
load();
}
private void load() {
textMessage.setVisibility(View.GONE);
swipeRefreshLayout.post(new Runnable() {
@Override
public void run() {
if (swipeRefreshLayout != null) {
swipeRefreshLayout.setRefreshing(true);
}
}
});
App.get().getGitLab().getLabels(projectId)
.compose(this.<List<Label>>bindToLifecycle())
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new CustomSingleObserver<List<Label>>() {
@Override
public void error(@NonNull Throwable t) {
Timber.e(t);
swipeRefreshLayout.setRefreshing(false);
textMessage.setVisibility(View.VISIBLE);
}
@Override
public void success(@NonNull List<Label> labels) {
swipeRefreshLayout.setRefreshing(false);
if (labels.isEmpty()) {
textMessage.setVisibility(View.VISIBLE);
}
adapterLabel.setItems(labels);
}
});
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
switch (requestCode) {
case REQUEST_NEW_LABEL:
if (resultCode == RESULT_OK) {
Label newLabel = Parcels.unwrap(data.getParcelableExtra(AddNewLabelActivity.KEY_NEW_LABEL));
adapterLabel.addLabel(newLabel);
}
break;
}
}
}
package com.commit451.gitlab.activity
import android.app.Activity
import android.content.Context
import android.content.Intent
import android.os.Bundle
import android.os.Parcelable
import android.support.v4.widget.SwipeRefreshLayout
import android.support.v7.widget.LinearLayoutManager
import android.support.v7.widget.RecyclerView
import android.support.v7.widget.Toolbar
import android.view.View
import android.view.ViewGroup
import android.widget.TextView
import butterknife.BindView
import butterknife.ButterKnife
import com.commit451.gitlab.App
import com.commit451.gitlab.R
import com.commit451.gitlab.R.string.labels
import com.commit451.gitlab.adapter.LabelAdapter
import com.commit451.gitlab.model.api.Label
import com.commit451.gitlab.navigation.Navigator
import com.commit451.gitlab.rx.CustomSingleObserver
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.schedulers.Schedulers
import org.parceler.Parcels
import timber.log.Timber
/**
* Add labels!
*/
class AddLabelActivity : BaseActivity() {
companion object {
private val KEY_PROJECT_ID = "project_id"
private val REQUEST_NEW_LABEL = 1
val KEY_LABEL = "label"
fun newIntent(context: Context, projectId: Long): Intent {
val intent = Intent(context, AddLabelActivity::class.java)
intent.putExtra(KEY_PROJECT_ID, projectId)
return intent
}
}
@BindView(R.id.root)
lateinit var root: ViewGroup
@BindView(R.id.toolbar)
lateinit var toolbar: Toolbar
@BindView(R.id.swipe_layout)
lateinit var swipeRefreshLayout: SwipeRefreshLayout
@BindView(R.id.list)
lateinit var list: RecyclerView
@BindView(R.id.message_text)
lateinit var textMessage: TextView
lateinit var adapterLabel: LabelAdapter
var projectId: Long = 0
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_add_label)
ButterKnife.bind(this)
projectId = intent.getLongExtra(KEY_PROJECT_ID, -1)
toolbar.setTitle(labels)
toolbar.inflateMenu(R.menu.menu_add_label)
toolbar.setOnMenuItemClickListener(Toolbar.OnMenuItemClickListener { item ->
when (item.itemId) {
R.id.action_add_label -> {
Navigator.navigateToAddNewLabel(this@AddLabelActivity, projectId, REQUEST_NEW_LABEL)
return@OnMenuItemClickListener true
}
}
false
})
swipeRefreshLayout.setOnRefreshListener { load() }
adapterLabel = LabelAdapter(LabelAdapter.Listener { label, viewHolder ->
val data = Intent()
data.putExtra(KEY_LABEL, Parcels.wrap(label))
setResult(Activity.RESULT_OK, data)
finish()
})
list.adapter = adapterLabel
list.layoutManager = LinearLayoutManager(this)
toolbar.setNavigationIcon(R.drawable.ic_back_24dp)
toolbar.setNavigationOnClickListener { onBackPressed() }
load()
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent) {
super.onActivityResult(requestCode, resultCode, data)
when (requestCode) {
REQUEST_NEW_LABEL -> if (resultCode == Activity.RESULT_OK) {
val newLabel = Parcels.unwrap<Label>(data.getParcelableExtra<Parcelable>(AddNewLabelActivity.KEY_NEW_LABEL))
adapterLabel.addLabel(newLabel)
}
}
}
fun load() {
textMessage.visibility = View.GONE
swipeRefreshLayout.isRefreshing = true
App.get().gitLab.getLabels(projectId)
.compose(this.bindToLifecycle<List<Label>>())
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(object : CustomSingleObserver<List<Label>>() {
override fun error(t: Throwable) {
Timber.e(t)
swipeRefreshLayout.isRefreshing = false
textMessage.visibility = View.VISIBLE
}
override fun success(labels: List<Label>) {
swipeRefreshLayout.isRefreshing = false
if (labels.isEmpty()) {
textMessage.visibility = View.VISIBLE
}
adapterLabel.setItems(labels)
}
})
}
}
package com.commit451.gitlab.activity;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.design.widget.Snackbar;
import android.support.design.widget.TextInputLayout;
import android.support.v7.widget.Toolbar;
import android.text.TextUtils;
import android.view.MenuItem;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.FrameLayout;
import com.commit451.easel.Easel;
import com.commit451.gitlab.App;
import com.commit451.gitlab.R;
import com.commit451.gitlab.event.MilestoneChangedEvent;
import com.commit451.gitlab.event.MilestoneCreatedEvent;
import com.commit451.gitlab.model.api.Milestone;
import com.commit451.gitlab.rx.CustomSingleObserver;
import com.commit451.teleprinter.Teleprinter;
import com.wdullaer.materialdatetimepicker.date.DatePickerDialog;
import org.parceler.Parcels;
import java.util.Calendar;
import java.util.Date;
import butterknife.BindView;
import butterknife.ButterKnife;
import butterknife.OnClick;
import io.reactivex.Single;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.schedulers.Schedulers;
import timber.log.Timber;
public class AddMilestoneActivity extends MorphActivity {
private static final String KEY_PROJECT_ID = "project_id";
private static final String KEY_MILESTONE = "milestone";
public static Intent newIntent(Context context, long projectId) {
return newIntent(context, projectId, null);
}
public static Intent newIntent(Context context, long projectId, Milestone milestone) {
Intent intent = new Intent(context, AddMilestoneActivity.class);
intent.putExtra(KEY_PROJECT_ID, projectId);
if (milestone != null) {
intent.putExtra(KEY_MILESTONE, Parcels.wrap(milestone));
}
return intent;
}
@BindView(R.id.root)
FrameLayout root;
@BindView(R.id.toolbar)
Toolbar toolbar;
@BindView(R.id.title_text_input_layout)
TextInputLayout textInputLayoutTitle;
@BindView(R.id.title)
EditText textTitle;
@BindView(R.id.description)
EditText textDescription;
@BindView(R.id.due_date)
Button buttonDueDate;
@BindView(R.id.progress)
View progress;
Teleprinter teleprinter;
long projectId;
Milestone milestone;
Date currentDate;
private final DatePickerDialog.OnDateSetListener onDateSetListener = new DatePickerDialog.OnDateSetListener() {
@Override
public void onDateSet(DatePickerDialog view, int year, int monthOfYear, int dayOfMonth) {
Calendar calendar = Calendar.getInstance();
calendar.set(Calendar.YEAR, year);
calendar.set(Calendar.MONTH, monthOfYear);
calendar.set(Calendar.DAY_OF_MONTH, dayOfMonth);
currentDate = calendar.getTime();
bind(currentDate);
}
};
@OnClick(R.id.due_date)
void onDueDateClicked() {
Calendar now = Calendar.getInstance();
if (currentDate != null) {
now.setTime(currentDate);
}
DatePickerDialog dpd = DatePickerDialog.newInstance(
onDateSetListener,
now.get(Calendar.YEAR),
now.get(Calendar.MONTH),
now.get(Calendar.DAY_OF_MONTH)
);
dpd.setAccentColor(Easel.getThemeAttrColor(this, R.attr.colorAccent));
dpd.show(getFragmentManager(), "date_picker");
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_add_milestone);
ButterKnife.bind(this);
morph(root);
teleprinter = new Teleprinter(this);
projectId = getIntent().getLongExtra(KEY_PROJECT_ID, -1);
milestone = Parcels.unwrap(getIntent().getParcelableExtra(KEY_MILESTONE));
if (milestone != null) {
bind(milestone);
toolbar.inflateMenu(R.menu.menu_edit_milestone);
} else {
toolbar.inflateMenu(R.menu.menu_add_milestone);
}
toolbar.setNavigationIcon(R.drawable.ic_back_24dp);
toolbar.setNavigationOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
onBackPressed();
}
});
toolbar.setOnMenuItemClickListener(new Toolbar.OnMenuItemClickListener() {
@Override
public boolean onMenuItemClick(MenuItem item) {
switch (item.getItemId()) {
case R.id.action_create:
case R.id.action_edit:
createMilestone();
return true;
}
return false;
}
});
}
private void createMilestone() {
teleprinter.hideKeyboard();
if (TextUtils.isEmpty(textTitle.getText())) {
textInputLayoutTitle.setError(getString(R.string.required_field));
return;
}
progress.setVisibility(View.VISIBLE);
String dueDate = null;
if (currentDate != null) {
dueDate = Milestone.DUE_DATE_FORMAT.format(currentDate);
}
if (milestone == null) {
createOrEditMilestone(App.get().getGitLab().createMilestone(projectId,
textTitle.getText().toString(),
textDescription.getText().toString(),
dueDate));
} else {
createOrEditMilestone(App.get().getGitLab().editMilestone(projectId,
milestone.getId(),
textTitle.getText().toString(),
textDescription.getText().toString(),
dueDate));
}
}
private void createOrEditMilestone(Single<Milestone> observable) {
observable.subscribeOn(Schedulers.io())
.compose(this.<Milestone>bindToLifecycle())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new CustomSingleObserver<Milestone>() {
@Override
public void error(@NonNull Throwable t) {
Timber.e(t);
progress.setVisibility(View.GONE);
showError();
}
@Override
public void success(@NonNull Milestone milestone) {
progress.setVisibility(View.GONE);
if (AddMilestoneActivity.this.milestone == null) {
App.bus().post(new MilestoneCreatedEvent(milestone));
} else {
App.bus().post(new MilestoneChangedEvent(milestone));
}
finish();
}
});
}
private void showError() {
Snackbar.make(root, getString(R.string.failed_to_create_milestone), Snackbar.LENGTH_SHORT)
.show();
}
private void bind(Date date) {
buttonDueDate.setText(Milestone.DUE_DATE_FORMAT.format(date));
}
private void bind(Milestone milestone) {
textTitle.setText(milestone.getTitle());
if (milestone.getDescription() != null) {
textDescription.setText(milestone.getDescription());
}
if (milestone.getDueDate() != null) {
currentDate = milestone.getDueDate();
bind(currentDate);
}
}
}
package com.commit451.gitlab.activity
import android.content.Context
import android.content.Intent
import android.os.Bundle
import android.os.Parcelable
import android.support.design.widget.Snackbar
import android.support.design.widget.TextInputLayout
import android.support.v7.widget.Toolbar
import android.text.TextUtils
import android.view.View
import android.widget.Button
import android.widget.EditText
import android.widget.FrameLayout
import butterknife.BindView
import butterknife.ButterKnife
import butterknife.OnClick
import com.commit451.easel.Easel
import com.commit451.gitlab.App
import com.commit451.gitlab.R
import com.commit451.gitlab.event.MilestoneChangedEvent
import com.commit451.gitlab.event.MilestoneCreatedEvent
import com.commit451.gitlab.model.api.Milestone
import com.commit451.gitlab.rx.CustomSingleObserver
import com.commit451.teleprinter.Teleprinter
import com.wdullaer.materialdatetimepicker.date.DatePickerDialog
import io.reactivex.Single
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.schedulers.Schedulers
import org.parceler.Parcels
import timber.log.Timber
import java.util.*
class AddMilestoneActivity : MorphActivity() {
companion object {
private val KEY_PROJECT_ID = "project_id"
private val KEY_MILESTONE = "milestone"
@JvmOverloads fun newIntent(context: Context, projectId: Long, milestone: Milestone? = null): Intent {
val intent = Intent(context, AddMilestoneActivity::class.java)
intent.putExtra(KEY_PROJECT_ID, projectId)
if (milestone != null) {
intent.putExtra(KEY_MILESTONE, Parcels.wrap(milestone))
}
return intent
}
}
@BindView(R.id.root)
lateinit var root: FrameLayout
@BindView(R.id.toolbar)
lateinit var toolbar: Toolbar
@BindView(R.id.title_text_input_layout)
lateinit var textInputLayoutTitle: TextInputLayout
@BindView(R.id.title)
lateinit var textTitle: EditText
@BindView(R.id.description)
lateinit var textDescription: EditText
@BindView(R.id.due_date)
lateinit var buttonDueDate: Button
@BindView(R.id.progress)
lateinit var progress: View
lateinit var teleprinter: Teleprinter
var projectId: Long = 0
var milestone: Milestone? = null
var currentDate: Date? = null
val onDateSetListener = DatePickerDialog.OnDateSetListener { view, year, monthOfYear, dayOfMonth ->
val calendar = Calendar.getInstance()
calendar.set(Calendar.YEAR, year)
calendar.set(Calendar.MONTH, monthOfYear)
calendar.set(Calendar.DAY_OF_MONTH, dayOfMonth)
currentDate = calendar.time
bind(currentDate!!)
}
@OnClick(R.id.due_date)
fun onDueDateClicked() {
val now = Calendar.getInstance()
if (currentDate != null) {
now.time = currentDate
}
val dpd = DatePickerDialog.newInstance(
onDateSetListener,
now.get(Calendar.YEAR),
now.get(Calendar.MONTH),
now.get(Calendar.DAY_OF_MONTH)
)
dpd.accentColor = Easel.getThemeAttrColor(this, R.attr.colorAccent)
dpd.show(fragmentManager, "date_picker")
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_add_milestone)
ButterKnife.bind(this)
morph(root)
teleprinter = Teleprinter(this)
projectId = intent.getLongExtra(KEY_PROJECT_ID, -1)
milestone = Parcels.unwrap<Milestone>(intent.getParcelableExtra<Parcelable>(KEY_MILESTONE))
if (milestone != null) {
bind(milestone!!)
toolbar.inflateMenu(R.menu.menu_edit_milestone)
} else {
toolbar.inflateMenu(R.menu.menu_add_milestone)
}
toolbar.setNavigationIcon(R.drawable.ic_back_24dp)
toolbar.setNavigationOnClickListener { onBackPressed() }
toolbar.setOnMenuItemClickListener(Toolbar.OnMenuItemClickListener { item ->
when (item.itemId) {
R.id.action_create, R.id.action_edit -> {
createMilestone()
return@OnMenuItemClickListener true
}
}
false
})
}
fun createMilestone() {
teleprinter.hideKeyboard()
if (TextUtils.isEmpty(textTitle.text)) {
textInputLayoutTitle.error = getString(R.string.required_field)
return
}
progress.visibility = View.VISIBLE
var dueDate: String? = null
if (currentDate != null) {
dueDate = Milestone.DUE_DATE_FORMAT.format(currentDate)
}
if (milestone == null) {
createOrEditMilestone(App.get().gitLab.createMilestone(projectId,
textTitle.text.toString(),
textDescription.text.toString(),
dueDate))
} else {
createOrEditMilestone(App.get().gitLab.editMilestone(projectId,
milestone!!.id,
textTitle.text.toString(),
textDescription.text.toString(),
dueDate))
}
}
fun createOrEditMilestone(observable: Single<Milestone>) {
observable.subscribeOn(Schedulers.io())
.compose(this.bindToLifecycle<Milestone>())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(object : CustomSingleObserver<Milestone>() {
override fun error(t: Throwable) {
Timber.e(t)
progress.visibility = View.GONE
showError()
}
override fun success(milestone: Milestone) {
progress.visibility = View.GONE
if (this@AddMilestoneActivity.milestone == null) {
App.bus().post(MilestoneCreatedEvent(milestone))
} else {
App.bus().post(MilestoneChangedEvent(milestone))
}
finish()
}
})
}
fun showError() {
Snackbar.make(root, getString(R.string.failed_to_create_milestone), Snackbar.LENGTH_SHORT)
.show()
}
fun bind(date: Date) {
buttonDueDate.text = Milestone.DUE_DATE_FORMAT.format(date)
}
fun bind(milestone: Milestone) {
textTitle.setText(milestone.title)
if (milestone.description != null) {
textDescription.setText(milestone.description)
}
if (milestone.dueDate != null) {
currentDate = milestone.dueDate
bind(currentDate!!)
}
}
}
package com.commit451.gitlab.activity;
import android.content.Context;
import android.content.Intent;
import android.graphics.drawable.ColorDrawable;
import android.os.Bundle;
import android.support.annotation.ColorInt;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.design.widget.Snackbar;
import android.support.design.widget.TextInputLayout;
import android.support.v7.widget.Toolbar;
import android.text.TextUtils;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
import com.afollestad.materialdialogs.color.ColorChooserDialog;
import com.commit451.gitlab.App;
import com.commit451.gitlab.R;
import com.commit451.gitlab.model.api.Label;
import com.commit451.gitlab.rx.CustomResponseSingleObserver;
import com.commit451.gitlab.util.ColorUtil;
import com.commit451.gitlab.util.Validator;
import com.jakewharton.retrofit2.adapter.rxjava2.HttpException;
import org.parceler.Parcels;
import butterknife.BindView;
import butterknife.ButterKnife;
import butterknife.OnClick;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.schedulers.Schedulers;
import retrofit2.Response;
import timber.log.Timber;
/**
* Create a brand new label
*/
public class AddNewLabelActivity extends BaseActivity implements ColorChooserDialog.ColorCallback {
private static final String KEY_PROJECT_ID = "project_id";
public static final String KEY_NEW_LABEL = "new_label";
public static Intent newIntent(Context context, long projectId) {
Intent intent = new Intent(context, AddNewLabelActivity.class);
intent.putExtra(KEY_PROJECT_ID, projectId);
return intent;
}
@BindView(R.id.root)
ViewGroup root;
@BindView(R.id.toolbar)
Toolbar toolbar;
@BindView(R.id.title_text_input_layout)
TextInputLayout textInputLayoutTitle;
@BindView(R.id.description)
TextView textDescription;
@BindView(R.id.image_color)
ImageView imageColor;
@BindView(R.id.progress)
View progress;
int chosenColor = -1;
@OnClick(R.id.root_color)
void onChooseColorClicked() {
// Pass AppCompatActivity which implements ColorCallback, along with the textTitle of the dialog
new ColorChooserDialog.Builder(this, R.string.add_new_label_choose_color)
.preselect(chosenColor)
.show();
}
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_add_new_label);
ButterKnife.bind(this);
toolbar.setNavigationIcon(R.drawable.ic_back_24dp);
toolbar.setNavigationOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
onBackPressed();
}
});
toolbar.inflateMenu(R.menu.menu_add_new_label);
toolbar.setOnMenuItemClickListener(new Toolbar.OnMenuItemClickListener() {
@Override
public boolean onMenuItemClick(MenuItem item) {
switch (item.getItemId()) {
case R.id.action_create:
createLabel();
return true;
}
return false;
}
});
}
@Override
public void onColorSelection(@NonNull ColorChooserDialog dialog, @ColorInt int selectedColor) {
chosenColor = selectedColor;
imageColor.setImageDrawable(new ColorDrawable(selectedColor));
}
private long getProjectId() {
return getIntent().getLongExtra(KEY_PROJECT_ID, -1);
}
private void createLabel() {
if (Validator.validateFieldsNotEmpty(getString(R.string.required_field), textInputLayoutTitle)) {
if (chosenColor == -1) {
Snackbar.make(root, R.string.add_new_label_color_is_required, Snackbar.LENGTH_SHORT)
.show();
return;
}
String title = textInputLayoutTitle.getEditText().getText().toString();
String description = null;
if (!TextUtils.isEmpty(textDescription.getText())) {
description = textDescription.getText().toString();
}
String color = null;
if (chosenColor != -1) {
color = ColorUtil.convertColorIntToString(chosenColor);
Timber.d("Setting color to %s", color);
}
progress.setVisibility(View.VISIBLE);
progress.setAlpha(0.0f);
progress.animate().alpha(1.0f);
App.get().getGitLab().createLabel(getProjectId(), title, color, description)
.compose(this.<Response<Label>>bindToLifecycle())
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new CustomResponseSingleObserver<Label>() {
@Override
public void error(@NonNull Throwable e) {
Timber.e(e);
progress.setVisibility(View.GONE);
if (e instanceof HttpException && ((HttpException) e).response().code() == 409) {
Snackbar.make(root, R.string.label_already_exists, Snackbar.LENGTH_SHORT)
.show();
} else {
Snackbar.make(root, R.string.failed_to_create_label, Snackbar.LENGTH_SHORT)
.show();
}
}
@Override
public void responseSuccess(@NonNull Label label) {
Intent data = new Intent();
data.putExtra(KEY_NEW_LABEL, Parcels.wrap(label));
setResult(RESULT_OK, data);
finish();
}
});
}
}
}
package com.commit451.gitlab.activity
import android.app.Activity
import android.content.Context
import android.content.Intent
import android.graphics.drawable.ColorDrawable
import android.os.Bundle
import android.support.annotation.ColorInt
import android.support.design.widget.Snackbar
import android.support.design.widget.TextInputLayout
import android.support.v7.widget.Toolbar
import android.text.TextUtils
import android.view.View
import android.view.ViewGroup
import android.widget.ImageView
import android.widget.TextView
import butterknife.BindView
import butterknife.ButterKnife
import butterknife.OnClick
import com.afollestad.materialdialogs.color.ColorChooserDialog
import com.commit451.gitlab.App
import com.commit451.gitlab.R
import com.commit451.gitlab.model.api.Label
import com.commit451.gitlab.rx.CustomResponseSingleObserver
import com.commit451.gitlab.util.ColorUtil
import com.commit451.gitlab.util.Validator
import com.jakewharton.retrofit2.adapter.rxjava2.HttpException
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.schedulers.Schedulers
import org.parceler.Parcels
import retrofit2.Response
import timber.log.Timber
/**
* Create a brand new label
*/
class AddNewLabelActivity : BaseActivity(), ColorChooserDialog.ColorCallback {
companion object {
private val KEY_PROJECT_ID = "project_id"
val KEY_NEW_LABEL = "new_label"
fun newIntent(context: Context, projectId: Long): Intent {
val intent = Intent(context, AddNewLabelActivity::class.java)
intent.putExtra(KEY_PROJECT_ID, projectId)
return intent
}
}
@BindView(R.id.root)
lateinit var root: ViewGroup
@BindView(R.id.toolbar)
lateinit var toolbar: Toolbar
@BindView(R.id.title_text_input_layout)
lateinit var textInputLayoutTitle: TextInputLayout
@BindView(R.id.description)
lateinit var textDescription: TextView
@BindView(R.id.image_color)
lateinit var imageColor: ImageView
@BindView(R.id.progress)
lateinit var progress: View
var chosenColor = -1
@OnClick(R.id.root_color)
fun onChooseColorClicked() {
// Pass AppCompatActivity which implements ColorCallback, along with the textTitle of the dialog
ColorChooserDialog.Builder(this, R.string.add_new_label_choose_color)
.preselect(chosenColor)
.show()
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_add_new_label)
ButterKnife.bind(this)
toolbar.setNavigationIcon(R.drawable.ic_back_24dp)
toolbar.setNavigationOnClickListener { onBackPressed() }
toolbar.inflateMenu(R.menu.menu_add_new_label)
toolbar.setOnMenuItemClickListener(Toolbar.OnMenuItemClickListener { item ->
when (item.itemId) {
R.id.action_create -> {
createLabel()
return@OnMenuItemClickListener true
}
}
false
})
}
override fun onColorSelection(dialog: ColorChooserDialog, @ColorInt selectedColor: Int) {
chosenColor = selectedColor
imageColor.setImageDrawable(ColorDrawable(selectedColor))
}
private val projectId: Long
get() = intent.getLongExtra(KEY_PROJECT_ID, -1)
private fun createLabel() {
if (Validator.validateFieldsNotEmpty(getString(R.string.required_field), textInputLayoutTitle)) {
if (chosenColor == -1) {
Snackbar.make(root, R.string.add_new_label_color_is_required, Snackbar.LENGTH_SHORT)
.show()
return
}
val title = textInputLayoutTitle.editText!!.text.toString()
var description: String? = null
if (!TextUtils.isEmpty(textDescription.text)) {
description = textDescription.text.toString()
}
var color: String? = null
if (chosenColor != -1) {
color = ColorUtil.convertColorIntToString(chosenColor)
Timber.d("Setting color to %s", color)
}
progress.visibility = View.VISIBLE
progress.alpha = 0.0f
progress.animate().alpha(1.0f)
App.get().gitLab.createLabel(projectId, title, color, description)
.compose(this.bindToLifecycle<Response<Label>>())
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(object : CustomResponseSingleObserver<Label>() {
override fun error(e: Throwable) {
Timber.e(e)
progress.visibility = View.GONE
if (e is HttpException && e.response().code() == 409) {
Snackbar.make(root, R.string.label_already_exists, Snackbar.LENGTH_SHORT)
.show()
} else {
Snackbar.make(root, R.string.failed_to_create_label, Snackbar.LENGTH_SHORT)
.show()
}
}
override fun responseSuccess(label: Label) {
val data = Intent()
data.putExtra(KEY_NEW_LABEL, Parcels.wrap(label))
setResult(Activity.RESULT_OK, data)
finish()
}
})
}
}
}
package com.commit451.gitlab.activity;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.design.widget.Snackbar;
import android.support.v4.widget.SwipeRefreshLayout;
import android.support.v7.widget.GridLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.Toolbar;
import android.text.TextUtils;
import android.view.View;
import android.view.ViewGroup;
import android.widget.EditText;
import com.commit451.alakazam.HideRunnable;
import com.commit451.gitlab.App;
import com.commit451.gitlab.R;
import com.commit451.gitlab.adapter.UserAdapter;
import com.commit451.gitlab.dialog.AccessDialog;
import com.commit451.gitlab.event.MemberAddedEvent;
import com.commit451.gitlab.model.api.Group;
import com.commit451.gitlab.model.api.Member;
import com.commit451.gitlab.model.api.UserBasic;
import com.commit451.gitlab.rx.CustomResponseSingleObserver;
import com.commit451.gitlab.util.LinkHeaderParser;
import com.commit451.gitlab.viewHolder.UserViewHolder;
import com.commit451.teleprinter.Teleprinter;
import com.jakewharton.retrofit2.adapter.rxjava2.HttpException;
import org.parceler.Parcels;
import java.util.List;
import butterknife.BindView;
import butterknife.ButterKnife;
import butterknife.OnClick;
import butterknife.OnEditorAction;
import butterknife.OnTextChanged;
import io.reactivex.Single;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.schedulers.Schedulers;
import retrofit2.Response;
import timber.log.Timber;
/**
* Add a new user to the repo or to the group, depending on the mode
*/
public class AddUserActivity extends MorphActivity {
private static final String KEY_PROJECT_ID = "project_id";
private static final String KEY_GROUP = "group";
public static Intent newIntent(Context context, long projectId) {
Intent intent = new Intent(context, AddUserActivity.class);
intent.putExtra(KEY_PROJECT_ID, projectId);
return intent;
}
public static Intent newIntent(Context context, Group group) {
Intent intent = new Intent(context, AddUserActivity.class);
intent.putExtra(KEY_GROUP, Parcels.wrap(group));
return intent;
}
@BindView(R.id.root)
ViewGroup root;
@BindView(R.id.toolbar)
Toolbar toolbar;
@BindView(R.id.search)
EditText textSearch;
@BindView(R.id.swipe_layout)
SwipeRefreshLayout swipeRefreshLayout;
@BindView(R.id.list)
RecyclerView list;
@BindView(R.id.clear)
View buttonClear;
GridLayoutManager layoutManager;
UserAdapter adapter;
AccessDialog dialogAccess;
UserBasic selectedUser;
Teleprinter teleprinter;
long projectId;
Group group;
String query;
Uri nextPageUrl;
boolean loading = false;
@OnClick(R.id.clear)
void onClearClick() {
buttonClear.animate().alpha(0.0f).withEndAction(new Runnable() {
@Override
public void run() {
buttonClear.setVisibility(View.GONE);
textSearch.getText().clear();
teleprinter.showKeyboard(textSearch);
}
});
}
@OnEditorAction(R.id.search)
boolean onEditorAction() {
if (!TextUtils.isEmpty(textSearch.getText())) {
query = textSearch.getText().toString();
loadData();
}
return true;
}
@OnTextChanged(R.id.search)
void onTextChanged(CharSequence s, int start, int before, int count) {
if (TextUtils.isEmpty(s)) {
buttonClear.animate()
.alpha(0.0f)
.withEndAction(new HideRunnable(buttonClear));
} else {
buttonClear.setVisibility(View.VISIBLE);
buttonClear.animate().alpha(1.0f);
}
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_add_user);
ButterKnife.bind(this);
teleprinter = new Teleprinter(this);
projectId = getIntent().getLongExtra(KEY_PROJECT_ID, -1);
group = Parcels.unwrap(getIntent().getParcelableExtra(KEY_GROUP));
dialogAccess = new AccessDialog(this, new AccessDialog.Listener() {
@Override
public void onAccessApplied(int accessLevel) {
dialogAccess.showLoading();
if (group == null) {
add(App.get().getGitLab().addProjectMember(projectId, selectedUser.getId(), accessLevel));
} else {
add(App.get().getGitLab().addGroupMember(projectId, selectedUser.getId(), accessLevel));
}
}
});
toolbar.setNavigationIcon(R.drawable.ic_back_24dp);
toolbar.setNavigationOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
onBackPressed();
}
});
adapter = new UserAdapter(new UserAdapter.Listener() {
@Override
public void onUserClicked(UserBasic user, UserViewHolder userViewHolder) {
selectedUser = user;
dialogAccess.show();
}
});
swipeRefreshLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
@Override
public void onRefresh() {
loadData();
}
});
list.setAdapter(adapter);
layoutManager = new GridLayoutManager(this, 2);
layoutManager.setSpanSizeLookup(adapter.getSpanSizeLookup());
list.setLayoutManager(layoutManager);
list.addOnScrollListener(new RecyclerView.OnScrollListener() {
@Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
int visibleItemCount = layoutManager.getChildCount();
int totalItemCount = layoutManager.getItemCount();
int firstVisibleItem = layoutManager.findFirstVisibleItemPosition();
if (firstVisibleItem + visibleItemCount >= totalItemCount && !loading && nextPageUrl != null) {
loadMore();
}
}
});
morph(root);
}
private void loadData() {
teleprinter.hideKeyboard();
swipeRefreshLayout.setRefreshing(true);
loading = true;
App.get().getGitLab().searchUsers(query)
.compose(this.<Response<List<UserBasic>>>bindToLifecycle())
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new CustomResponseSingleObserver<List<UserBasic>>() {
@Override
public void error(@NonNull Throwable t) {
Timber.e(t);
swipeRefreshLayout.setRefreshing(false);
loading = false;
Snackbar.make(root, getString(R.string.connection_error_users), Snackbar.LENGTH_SHORT)
.show();
}
@Override
public void responseSuccess(@NonNull List<UserBasic> users) {
swipeRefreshLayout.setRefreshing(false);
loading = false;
adapter.setData(users);
nextPageUrl = LinkHeaderParser.parse(response()).getNext();
Timber.d("Next page url is %s", nextPageUrl);
}
});
}
private void loadMore() {
loading = true;
adapter.setLoading(true);
Timber.d("loadMore " + nextPageUrl.toString() + " " + query);
App.get().getGitLab().searchUsers(nextPageUrl.toString(), query)
.compose(this.<Response<List<UserBasic>>>bindToLifecycle())
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new CustomResponseSingleObserver<List<UserBasic>>() {
@Override
public void error(@NonNull Throwable t) {
Timber.e(t);
adapter.setLoading(false);
}
@Override
public void responseSuccess(@NonNull List<UserBasic> users) {
loading = false;
adapter.setLoading(false);
adapter.addData(users);
nextPageUrl = LinkHeaderParser.parse(response()).getNext();
}
});
}
private void add(Single<Response<Member>> observable) {
observable.subscribeOn(Schedulers.io())
.compose(this.<Response<Member>>bindToLifecycle())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new CustomResponseSingleObserver<Member>() {
@Override
public void error(@NonNull Throwable t) {
Timber.e(t);
String message = getString(R.string.error_failed_to_add_user);
if (t instanceof HttpException) {
switch (((HttpException) t).code()) {
case 409:
message = getString(R.string.error_user_conflict);
}
}
Snackbar.make(root, message, Snackbar.LENGTH_SHORT)
.show();
}
@Override
public void responseSuccess(@NonNull Member member) {
Snackbar.make(root, R.string.user_added_successfully, Snackbar.LENGTH_SHORT)
.show();
dialogAccess.dismiss();
dismiss();
App.bus().post(new MemberAddedEvent(member));
}
});
}
}
package com.commit451.gitlab.activity
import android.content.Context
import android.content.Intent
import android.net.Uri
import android.os.Bundle
import android.os.Parcelable
import android.support.design.widget.Snackbar
import android.support.v4.widget.SwipeRefreshLayout
import android.support.v7.widget.GridLayoutManager
import android.support.v7.widget.RecyclerView
import android.support.v7.widget.Toolbar
import android.text.TextUtils
import android.view.View
import android.view.ViewGroup
import android.widget.EditText
import butterknife.*
import com.commit451.alakazam.HideRunnable
import com.commit451.gitlab.App
import com.commit451.gitlab.R
import com.commit451.gitlab.adapter.UserAdapter
import com.commit451.gitlab.dialog.AccessDialog
import com.commit451.gitlab.event.MemberAddedEvent
import com.commit451.gitlab.model.api.Group
import com.commit451.gitlab.model.api.Member
import com.commit451.gitlab.model.api.UserBasic
import com.commit451.gitlab.rx.CustomResponseSingleObserver
import com.commit451.gitlab.util.LinkHeaderParser
import com.commit451.teleprinter.Teleprinter
import com.jakewharton.retrofit2.adapter.rxjava2.HttpException
import io.reactivex.Single
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.schedulers.Schedulers
import org.parceler.Parcels
import retrofit2.Response
import timber.log.Timber
/**
* Add a new user to the repo or to the group, depending on the mode
*/
class AddUserActivity : MorphActivity() {
companion object {
private val KEY_PROJECT_ID = "project_id"
private val KEY_GROUP = "group"
fun newIntent(context: Context, projectId: Long): Intent {
val intent = Intent(context, AddUserActivity::class.java)
intent.putExtra(KEY_PROJECT_ID, projectId)
return intent
}
fun newIntent(context: Context, group: Group): Intent {
val intent = Intent(context, AddUserActivity::class.java)
intent.putExtra(KEY_GROUP, Parcels.wrap(group))
return intent
}
}
@BindView(R.id.root)
lateinit var root: ViewGroup
@BindView(R.id.toolbar)
lateinit var toolbar: Toolbar
@BindView(R.id.search)
lateinit var textSearch: EditText
@BindView(R.id.swipe_layout)
lateinit var swipeRefreshLayout: SwipeRefreshLayout
@BindView(R.id.list)
lateinit var list: RecyclerView
@BindView(R.id.clear)
lateinit var buttonClear: View
lateinit var layoutManager: GridLayoutManager
lateinit var adapter: UserAdapter
lateinit var dialogAccess: AccessDialog
lateinit var teleprinter: Teleprinter
var projectId: Long = 0
var group: Group? = null
var query: String? = null
var nextPageUrl: Uri? = null
var loading = false
var selectedUser: UserBasic? = null
@OnClick(R.id.clear)
fun onClearClick() {
buttonClear.animate().alpha(0.0f).withEndAction {
buttonClear.visibility = View.GONE
textSearch.text.clear()
teleprinter.showKeyboard(textSearch)
}
}
@OnEditorAction(R.id.search)
internal fun onEditorAction(): Boolean {
if (!TextUtils.isEmpty(textSearch.text)) {
query = textSearch.text.toString()
loadData()
}
return true
}
@OnTextChanged(R.id.search)
internal fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) {
if (TextUtils.isEmpty(s)) {
buttonClear.animate()
.alpha(0.0f)
.withEndAction(HideRunnable(buttonClear))
} else {
buttonClear.visibility = View.VISIBLE
buttonClear.animate().alpha(1.0f)
}
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_add_user)
ButterKnife.bind(this)
teleprinter = Teleprinter(this)
projectId = intent.getLongExtra(KEY_PROJECT_ID, -1)
group = Parcels.unwrap<Group>(intent.getParcelableExtra<Parcelable>(KEY_GROUP))
dialogAccess = AccessDialog(this, AccessDialog.Listener { accessLevel ->
dialogAccess.showLoading()
if (group == null) {
add(App.get().gitLab.addProjectMember(projectId, selectedUser!!.id, accessLevel))
} else {
add(App.get().gitLab.addGroupMember(projectId, selectedUser!!.id, accessLevel))
}
})
toolbar.setNavigationIcon(R.drawable.ic_back_24dp)
toolbar.setNavigationOnClickListener { onBackPressed() }
adapter = UserAdapter(UserAdapter.Listener { user, userViewHolder ->
selectedUser = user
dialogAccess.show()
})
swipeRefreshLayout.setOnRefreshListener { loadData() }
list.adapter = adapter
layoutManager = GridLayoutManager(this, 2)
layoutManager.spanSizeLookup = adapter.spanSizeLookup
list.layoutManager = layoutManager
list.addOnScrollListener(object : RecyclerView.OnScrollListener() {
override fun onScrolled(recyclerView: RecyclerView?, dx: Int, dy: Int) {
super.onScrolled(recyclerView, dx, dy)
val visibleItemCount = layoutManager.childCount
val totalItemCount = layoutManager.itemCount
val firstVisibleItem = layoutManager.findFirstVisibleItemPosition()
if (firstVisibleItem + visibleItemCount >= totalItemCount && !loading && nextPageUrl != null) {
loadMore()
}
}
})
morph(root)
}
private fun loadData() {
teleprinter.hideKeyboard()
swipeRefreshLayout.isRefreshing = true
loading = true
App.get().gitLab.searchUsers(query)
.compose(this.bindToLifecycle<Response<List<UserBasic>>>())
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(object : CustomResponseSingleObserver<List<UserBasic>>() {
override fun error(t: Throwable) {
Timber.e(t)
swipeRefreshLayout.isRefreshing = false
loading = false
Snackbar.make(root, getString(R.string.connection_error_users), Snackbar.LENGTH_SHORT)
.show()
}
override fun responseSuccess(users: List<UserBasic>) {
swipeRefreshLayout.isRefreshing = false
loading = false
adapter.setData(users)
nextPageUrl = LinkHeaderParser.parse(response()).next
Timber.d("Next page url is %s", nextPageUrl)
}
})
}
private fun loadMore() {
loading = true
adapter.setLoading(true)
Timber.d("loadMore " + nextPageUrl!!.toString() + " " + query)
App.get().gitLab.searchUsers(nextPageUrl!!.toString(), query)
.compose(this.bindToLifecycle<Response<List<UserBasic>>>())
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(object : CustomResponseSingleObserver<List<UserBasic>>() {
override fun error(t: Throwable) {
Timber.e(t)
adapter.setLoading(false)
}
override fun responseSuccess(users: List<UserBasic>) {
loading = false
adapter.setLoading(false)
adapter.addData(users)
nextPageUrl = LinkHeaderParser.parse(response()).next
}
})
}
private fun add(observable: Single<Response<Member>>) {
observable.subscribeOn(Schedulers.io())
.compose(this.bindToLifecycle<Response<Member>>())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(object : CustomResponseSingleObserver<Member>() {
override fun error(t: Throwable) {
Timber.e(t)
var message = getString(R.string.error_failed_to_add_user)
if (t is HttpException) {
when (t.code()) {
409 -> message = getString(R.string.error_user_conflict)
}
}
Snackbar.make(root, message, Snackbar.LENGTH_SHORT)
.show()
}
override fun responseSuccess(member: Member) {
Snackbar.make(root, R.string.user_added_successfully, Snackbar.LENGTH_SHORT)
.show()
dialogAccess.dismiss()
dismiss()
App.bus().post(MemberAddedEvent(member))
}
})
}
}
package com.commit451.gitlab.activity;
import android.animation.Animator;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.view.View;
import android.view.ViewGroup;
import android.view.animation.AccelerateDecelerateInterpolator;
import com.commit451.gitlab.App;
import com.commit451.gitlab.R;
import com.commit451.gitlab.model.api.FileUploadResponse;
import com.commit451.gitlab.model.api.Project;
import com.commit451.gitlab.rx.CustomSingleObserver;
import com.commit451.gitlab.rx.FileObservableFactory;
import org.parceler.Parcels;
import java.io.File;
import java.util.List;
import butterknife.BindView;
import butterknife.ButterKnife;
import butterknife.OnClick;
import io.codetail.animation.ViewAnimationUtils;
import io.reactivex.SingleSource;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.functions.Function;
import io.reactivex.schedulers.Schedulers;
import okhttp3.MultipartBody;
import pl.aprilapps.easyphotopicker.DefaultCallback;
import pl.aprilapps.easyphotopicker.EasyImage;
import timber.log.Timber;
/**
* Attaches files
*/
public class AttachActivity extends BaseActivity {
public static final String KEY_FILE_UPLOAD_RESPONSE = "response";
private static final String KEY_PROJECT = "project";
public static Intent newIntent(Context context, Project project) {
Intent intent = new Intent(context, AttachActivity.class);
intent.putExtra(KEY_PROJECT, Parcels.wrap(project));
return intent;
}
@BindView(R.id.root_buttons)
ViewGroup rootButtons;
@BindView(R.id.progress)
View progress;
@BindView(R.id.attachCard)
View card;
Project project;
@OnClick(R.id.root)
void onRootClicked() {
onBackPressed();
}
@OnClick(R.id.button_choose_photo)
void onChoosePhotoClicked() {
EasyImage.openGallery(this, 0, false);
}
@OnClick(R.id.button_take_photo)
void onTakePhotoClicked() {
EasyImage.openCamera(this, 0);
}
@OnClick(R.id.button_choose_file)
void onChooseFileClicked() {
EasyImage.openChooserWithDocuments(this, "Choose file", 0);
}
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_attach);
ButterKnife.bind(this);
//Run the runnable after the view has been measured
card.post(new Runnable() {
@Override
public void run() {
//we need the radius of the animation circle, which is the diagonal of the view
float finalRadius = (float) Math.hypot(card.getWidth(), card.getHeight());
//it's using a 3rd-party ViewAnimationUtils class for compat reasons (up to API 14)
Animator animator = ViewAnimationUtils
.createCircularReveal(card, 0, card.getHeight(), 0, finalRadius);
animator.setDuration(500);
animator.setInterpolator(new AccelerateDecelerateInterpolator());
animator.start();
}
});
project = Parcels.unwrap(getIntent().getParcelableExtra(KEY_PROJECT));
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
EasyImage.handleActivityResult(requestCode, resultCode, data, this, new DefaultCallback() {
@Override
public void onImagePickerError(Exception e, EasyImage.ImageSource source, int type) {
//Some error handling
}
@Override
public void onImagesPicked(List<File> imageFiles, EasyImage.ImageSource source, int type) {
onPhotoReturned(imageFiles.get(0));
}
@Override
public void onCanceled(EasyImage.ImageSource source, int type) {
//Cancel handling, you might wanna remove taken photo if it was canceled
if (source == EasyImage.ImageSource.CAMERA) {
File photoFile = EasyImage.lastlyTakenButCanceledPhoto(AttachActivity.this);
if (photoFile != null) {
photoFile.delete();
}
}
}
});
}
@Override
public void finish() {
super.finish();
overridePendingTransition(R.anim.do_nothing, R.anim.fade_out);
}
private void onPhotoReturned(File photo) {
progress.setVisibility(View.VISIBLE);
rootButtons.setVisibility(View.INVISIBLE);
FileObservableFactory.toPart(photo)
.flatMap(new Function<MultipartBody.Part, SingleSource<FileUploadResponse>>() {
@Override
public SingleSource<FileUploadResponse> apply(MultipartBody.Part part) throws Exception {
return App.get().getGitLab().uploadFile(project.getId(), part);
}
})
.compose(this.<FileUploadResponse>bindToLifecycle())
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new CustomSingleObserver<FileUploadResponse>() {
@Override
public void success(@NonNull FileUploadResponse fileUploadResponse) {
Intent data = new Intent();
data.putExtra(KEY_FILE_UPLOAD_RESPONSE, Parcels.wrap(fileUploadResponse));
setResult(RESULT_OK, data);
finish();
}
@Override
public void error(@NonNull Throwable t) {
Timber.e(t);
finish();
}
});
}
}
package com.commit451.gitlab.activity
import android.app.Activity
import android.content.Context
import android.content.Intent
import android.os.Bundle
import android.os.Parcelable
import android.view.View
import android.view.ViewGroup
import android.view.animation.AccelerateDecelerateInterpolator
import butterknife.BindView
import butterknife.ButterKnife
import butterknife.OnClick
import com.commit451.gitlab.App
import com.commit451.gitlab.R
import com.commit451.gitlab.model.api.FileUploadResponse
import com.commit451.gitlab.model.api.Project
import com.commit451.gitlab.rx.CustomSingleObserver
import com.commit451.gitlab.rx.FileObservableFactory
import io.codetail.animation.ViewAnimationUtils
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.schedulers.Schedulers
import org.parceler.Parcels
import pl.aprilapps.easyphotopicker.DefaultCallback
import pl.aprilapps.easyphotopicker.EasyImage
import timber.log.Timber
import java.io.File
/**
* Attaches files
*/
class AttachActivity : BaseActivity() {
companion object {
val KEY_FILE_UPLOAD_RESPONSE = "response"
private val KEY_PROJECT = "project"
fun newIntent(context: Context, project: Project): Intent {
val intent = Intent(context, AttachActivity::class.java)
intent.putExtra(KEY_PROJECT, Parcels.wrap(project))
return intent
}
}
@BindView(R.id.root_buttons)
lateinit var rootButtons: ViewGroup
@BindView(R.id.progress)
lateinit var progress: View
@BindView(R.id.attachCard)
lateinit var card: View
var project: Project?= null
@OnClick(R.id.root)
fun onRootClicked() {
onBackPressed()
}
@OnClick(R.id.button_choose_photo)
fun onChoosePhotoClicked() {
EasyImage.openGallery(this, 0, false)
}
@OnClick(R.id.button_take_photo)
fun onTakePhotoClicked() {
EasyImage.openCamera(this, 0)
}
@OnClick(R.id.button_choose_file)
fun onChooseFileClicked() {
EasyImage.openChooserWithDocuments(this, "Choose file", 0)
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_attach)
ButterKnife.bind(this)
//Run the runnable after the view has been measured
card.post {
//we need the radius of the animation circle, which is the diagonal of the view
val finalRadius = Math.hypot(card.width.toDouble(), card.height.toDouble()).toFloat()
//it's using a 3rd-party ViewAnimationUtils class for compat reasons (up to API 14)
val animator = ViewAnimationUtils
.createCircularReveal(card, 0, card.height, 0f, finalRadius)
animator.duration = 500
animator.interpolator = AccelerateDecelerateInterpolator()
animator.start()
}
project = Parcels.unwrap<Project>(intent.getParcelableExtra<Parcelable>(KEY_PROJECT))
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent) {
super.onActivityResult(requestCode, resultCode, data)
EasyImage.handleActivityResult(requestCode, resultCode, data, this, object : DefaultCallback() {
override fun onImagePickerError(e: Exception?, source: EasyImage.ImageSource?, type: Int) {
//Some error handling
}
override fun onImagesPicked(imageFiles: List<File>, source: EasyImage.ImageSource, type: Int) {
onPhotoReturned(imageFiles[0])
}
override fun onCanceled(source: EasyImage.ImageSource?, type: Int) {
//Cancel handling, you might wanna remove taken photo if it was canceled
if (source == EasyImage.ImageSource.CAMERA) {
val photoFile = EasyImage.lastlyTakenButCanceledPhoto(this@AttachActivity)
photoFile?.delete()
}
}
})
}
override fun finish() {
super.finish()
overridePendingTransition(R.anim.do_nothing, R.anim.fade_out)
}
fun onPhotoReturned(photo: File) {
progress.visibility = View.VISIBLE
rootButtons.visibility = View.INVISIBLE
FileObservableFactory.toPart(photo)
.flatMap { part -> App.get().gitLab.uploadFile(project!!.id, part) }
.compose(this.bindToLifecycle<FileUploadResponse>())
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(object : CustomSingleObserver<FileUploadResponse>() {
override fun success(fileUploadResponse: FileUploadResponse) {
val data = Intent()
data.putExtra(KEY_FILE_UPLOAD_RESPONSE, Parcels.wrap(fileUploadResponse))
setResult(Activity.RESULT_OK, data)
finish()
}
override fun error(t: Throwable) {
Timber.e(t)
finish()
}
})
}
}
package com.commit451.gitlab.activity;
import android.support.design.widget.TextInputLayout;
import android.text.TextUtils;
import com.commit451.gitlab.R;
import com.trello.rxlifecycle2.components.support.RxAppCompatActivity;
/**
* Base activity for others to derive from
*/
public class BaseActivity extends RxAppCompatActivity {
public boolean hasEmptyFields(TextInputLayout... textInputLayouts) {
boolean hasEmptyField = false;
for (TextInputLayout textInputLayout : textInputLayouts) {
if (TextUtils.isEmpty(textInputLayout.getEditText().getText())) {
textInputLayout.setError(getString(R.string.required_field));
hasEmptyField = true;
} else {
textInputLayout.setError(null);
}
}
return hasEmptyField;
}
}
package com.commit451.gitlab.activity
import android.support.design.widget.TextInputLayout
import android.text.TextUtils
import com.commit451.gitlab.R
import com.trello.rxlifecycle2.components.support.RxAppCompatActivity
/**
* Base activity for others to derive from
*/
open class BaseActivity : RxAppCompatActivity() {
fun hasEmptyFields(vararg textInputLayouts: TextInputLayout): Boolean {
var hasEmptyField = false
for (textInputLayout in textInputLayouts) {
if (TextUtils.isEmpty(textInputLayout.editText!!.text)) {
textInputLayout.error = getString(R.string.required_field)
hasEmptyField = true
} else {
textInputLayout.error = null
}
}
return hasEmptyField
}
}
package com.commit451.gitlab.activity;
import android.Manifest;
import android.annotation.TargetApi;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.design.widget.Snackbar;
import android.support.design.widget.TabLayout;
import android.support.v4.content.ContextCompat;
import android.support.v4.view.ViewPager;
import android.support.v7.widget.Toolbar;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import com.commit451.gitlab.App;
import com.commit451.gitlab.R;
import com.commit451.gitlab.adapter.BuildSectionsPagerAdapter;
import com.commit451.gitlab.event.BuildChangedEvent;
import com.commit451.gitlab.model.Account;
import com.commit451.gitlab.model.api.Build;
import com.commit451.gitlab.model.api.Project;
import com.commit451.gitlab.rx.CustomSingleObserver;
import com.commit451.gitlab.util.BuildUtil;
import com.commit451.gitlab.util.DownloadUtil;
import org.parceler.Parcels;
import butterknife.BindView;
import butterknife.ButterKnife;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.schedulers.Schedulers;
import timber.log.Timber;
/**
* Shows the details of a merge request
*/
public class BuildActivity extends BaseActivity {
private static final int REQUEST_PERMISSION_WRITE_STORAGE = 1337;
private static final String KEY_PROJECT = "key_project";
private static final String KEY_BUILD = "key_merge_request";
public static Intent newIntent(Context context, Project project, Build build) {
Intent intent = new Intent(context, BuildActivity.class);
intent.putExtra(KEY_PROJECT, Parcels.wrap(project));
intent.putExtra(KEY_BUILD, Parcels.wrap(build));
return intent;
}
@BindView(R.id.root)
ViewGroup root;
@BindView(R.id.toolbar)
Toolbar toolbar;
@BindView(R.id.tabs)
TabLayout tabLayout;
@BindView(R.id.pager)
ViewPager viewPager;
@BindView(R.id.progress)
View progress;
MenuItem menuItemDownload;
Project project;
Build build;
private final Toolbar.OnMenuItemClickListener onMenuItemClickListener = new Toolbar.OnMenuItemClickListener() {
@Override
public boolean onMenuItemClick(MenuItem item) {
switch (item.getItemId()) {
case R.id.action_retry:
progress.setVisibility(View.VISIBLE);
App.get().getGitLab().retryBuild(project.getId(), build.getId())
.compose(BuildActivity.this.<Build>bindToLifecycle())
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new CustomSingleObserver<Build>() {
@Override
public void error(@NonNull Throwable t) {
Timber.e(t);
progress.setVisibility(View.GONE);
Snackbar.make(root, R.string.unable_to_retry_build, Snackbar.LENGTH_LONG)
.show();
}
@Override
public void success(@NonNull Build build) {
progress.setVisibility(View.GONE);
Snackbar.make(root, R.string.build_started, Snackbar.LENGTH_LONG)
.show();
App.bus().post(new BuildChangedEvent(build));
}
});
return true;
case R.id.action_erase:
progress.setVisibility(View.VISIBLE);
App.get().getGitLab().eraseBuild(project.getId(), build.getId())
.compose(BuildActivity.this.<Build>bindToLifecycle())
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new CustomSingleObserver<Build>() {
@Override
public void error(@NonNull Throwable t) {
Timber.e(t);
progress.setVisibility(View.GONE);
Snackbar.make(root, R.string.unable_to_erase_build, Snackbar.LENGTH_LONG)
.show();
}
@Override
public void success(@NonNull Build build) {
progress.setVisibility(View.GONE);
Snackbar.make(root, R.string.build_erased, Snackbar.LENGTH_LONG)
.show();
App.bus().post(new BuildChangedEvent(build));
}
});
return true;
case R.id.action_cancel:
progress.setVisibility(View.VISIBLE);
App.get().getGitLab().cancelBuild(project.getId(), build.getId())
.compose(BuildActivity.this.<Build>bindToLifecycle())
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new CustomSingleObserver<Build>() {
@Override
public void error(@NonNull Throwable t) {
Timber.e(t);
progress.setVisibility(View.GONE);
Snackbar.make(root, R.string.unable_to_cancel_build, Snackbar.LENGTH_LONG)
.show();
}
@Override
public void success(@NonNull Build build) {
progress.setVisibility(View.GONE);
Snackbar.make(root, R.string.build_canceled, Snackbar.LENGTH_LONG)
.show();
App.bus().post(new BuildChangedEvent(build));
}
});
return true;
case R.id.action_download:
checkDownloadBuild();
return true;
}
return false;
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_build);
ButterKnife.bind(this);
project = Parcels.unwrap(getIntent().getParcelableExtra(KEY_PROJECT));
build = Parcels.unwrap(getIntent().getParcelableExtra(KEY_BUILD));
toolbar.setTitle(getString(R.string.build_number) + build.getId());
toolbar.setNavigationIcon(R.drawable.ic_back_24dp);
toolbar.setNavigationOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
onBackPressed();
}
});
toolbar.setSubtitle(project.getNameWithNamespace());
toolbar.inflateMenu(R.menu.menu_build);
toolbar.setOnMenuItemClickListener(onMenuItemClickListener);
menuItemDownload = toolbar.getMenu().findItem(R.id.action_download);
menuItemDownload.setVisible(build.getArtifactsFile() != null);
setupTabs();
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String permissions[], @NonNull int[] grantResults) {
switch (requestCode) {
case REQUEST_PERMISSION_WRITE_STORAGE: {
if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
downloadBuild();
}
}
}
}
private void setupTabs() {
BuildSectionsPagerAdapter sectionsPagerAdapter = new BuildSectionsPagerAdapter(
this,
getSupportFragmentManager(),
project,
build);
viewPager.setAdapter(sectionsPagerAdapter);
tabLayout.setupWithViewPager(viewPager);
}
@TargetApi(23)
private void checkDownloadBuild() {
if (ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED) {
downloadBuild();
} else {
requestPermissions(new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, REQUEST_PERMISSION_WRITE_STORAGE);
}
}
private void downloadBuild() {
Account account = App.get().getAccount();
String downloadUrl = BuildUtil.getDownloadBuildUrl(App.get().getAccount().getServerUrl(), project, build);
Timber.d("Downloading build: " + downloadUrl);
DownloadUtil.download(BuildActivity.this, account, downloadUrl, build.getArtifactsFile().getFileName());
}
}
package com.commit451.gitlab.activity
import android.Manifest
import android.annotation.TargetApi
import android.content.Context
import android.content.Intent
import android.content.pm.PackageManager
import android.os.Bundle
import android.os.Parcelable
import android.support.design.widget.Snackbar
import android.support.design.widget.TabLayout
import android.support.v4.content.ContextCompat
import android.support.v4.view.ViewPager
import android.support.v7.widget.Toolbar
import android.view.MenuItem
import android.view.View
import android.view.ViewGroup
import com.commit451.gitlab.App
import com.commit451.gitlab.R
import com.commit451.gitlab.adapter.BuildSectionsPagerAdapter
import com.commit451.gitlab.event.BuildChangedEvent
import com.commit451.gitlab.model.Account
import com.commit451.gitlab.model.api.Build
import com.commit451.gitlab.model.api.Project
import com.commit451.gitlab.rx.CustomSingleObserver
import com.commit451.gitlab.util.BuildUtil
import com.commit451.gitlab.util.DownloadUtil
import org.parceler.Parcels
import butterknife.BindView
import butterknife.ButterKnife
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.schedulers.Schedulers
import timber.log.Timber
/**
* Shows the details of a merge request
*/
class BuildActivity : BaseActivity() {
companion object {
private val REQUEST_PERMISSION_WRITE_STORAGE = 1337
private val KEY_PROJECT = "key_project"
private val KEY_BUILD = "key_merge_request"
fun newIntent(context: Context, project: Project, build: Build): Intent {
val intent = Intent(context, BuildActivity::class.java)
intent.putExtra(KEY_PROJECT, Parcels.wrap(project))
intent.putExtra(KEY_BUILD, Parcels.wrap(build))
return intent
}
}
@BindView(R.id.root)
lateinit var root: ViewGroup
@BindView(R.id.toolbar)
lateinit var toolbar: Toolbar
@BindView(R.id.tabs)
lateinit var tabLayout: TabLayout
@BindView(R.id.pager)
lateinit var viewPager: ViewPager
@BindView(R.id.progress)
lateinit var progress: View
lateinit var menuItemDownload: MenuItem
lateinit var project: Project
lateinit var build: Build
private val onMenuItemClickListener = Toolbar.OnMenuItemClickListener { item ->
when (item.itemId) {
R.id.action_retry -> {
progress.visibility = View.VISIBLE
App.get().gitLab.retryBuild(project.id, build.id)
.compose(this@BuildActivity.bindToLifecycle<Build>())
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(object : CustomSingleObserver<Build>() {
override fun error(t: Throwable) {
Timber.e(t)
progress.visibility = View.GONE
Snackbar.make(root, R.string.unable_to_retry_build, Snackbar.LENGTH_LONG)
.show()
}
override fun success(build: Build) {
progress.visibility = View.GONE
Snackbar.make(root, R.string.build_started, Snackbar.LENGTH_LONG)
.show()
App.bus().post(BuildChangedEvent(build))
}
})
return@OnMenuItemClickListener true
}
R.id.action_erase -> {
progress.visibility = View.VISIBLE
App.get().gitLab.eraseBuild(project.id, build.id)
.compose(this@BuildActivity.bindToLifecycle<Build>())
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(object : CustomSingleObserver<Build>() {
override fun error(t: Throwable) {
Timber.e(t)
progress.visibility = View.GONE
Snackbar.make(root, R.string.unable_to_erase_build, Snackbar.LENGTH_LONG)
.show()
}
override fun success(build: Build) {
progress.visibility = View.GONE
Snackbar.make(root, R.string.build_erased, Snackbar.LENGTH_LONG)
.show()
App.bus().post(BuildChangedEvent(build))
}
})
return@OnMenuItemClickListener true
}
R.id.action_cancel -> {
progress.visibility = View.VISIBLE
App.get().gitLab.cancelBuild(project.id, build.id)
.compose(this@BuildActivity.bindToLifecycle<Build>())
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(object : CustomSingleObserver<Build>() {
override fun error(t: Throwable) {
Timber.e(t)
progress.visibility = View.GONE
Snackbar.make(root, R.string.unable_to_cancel_build, Snackbar.LENGTH_LONG)
.show()
}
override fun success(build: Build) {
progress.visibility = View.GONE
Snackbar.make(root, R.string.build_canceled, Snackbar.LENGTH_LONG)
.show()
App.bus().post(BuildChangedEvent(build))
}
})
return@OnMenuItemClickListener true
}
R.id.action_download -> {
checkDownloadBuild()
return@OnMenuItemClickListener true
}
}
false
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_build)
ButterKnife.bind(this)
project = Parcels.unwrap<Project>(intent.getParcelableExtra<Parcelable>(KEY_PROJECT))
build = Parcels.unwrap<Build>(intent.getParcelableExtra<Parcelable>(KEY_BUILD))
toolbar.title = getString(R.string.build_number) + build.id
toolbar.setNavigationIcon(R.drawable.ic_back_24dp)
toolbar.setNavigationOnClickListener { onBackPressed() }
toolbar.subtitle = project.nameWithNamespace
toolbar.inflateMenu(R.menu.menu_build)
toolbar.setOnMenuItemClickListener(onMenuItemClickListener)
menuItemDownload = toolbar.menu.findItem(R.id.action_download)
menuItemDownload.isVisible = build.artifactsFile != null
setupTabs()
}
override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<String>, grantResults: IntArray) {
when (requestCode) {
REQUEST_PERMISSION_WRITE_STORAGE -> {
if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
downloadBuild()
}
}
}
}
private fun setupTabs() {
val sectionsPagerAdapter = BuildSectionsPagerAdapter(
this,
supportFragmentManager,
project,
build)
viewPager.adapter = sectionsPagerAdapter
tabLayout.setupWithViewPager(viewPager)
}
@TargetApi(23)
private fun checkDownloadBuild() {
if (ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED) {
downloadBuild()
} else {
requestPermissions(arrayOf(Manifest.permission.WRITE_EXTERNAL_STORAGE), REQUEST_PERMISSION_WRITE_STORAGE)
}
}
private fun downloadBuild() {
val account = App.get().account
val downloadUrl = BuildUtil.getDownloadBuildUrl(App.get().account.serverUrl, project, build)
Timber.d("Downloading build: " + downloadUrl)
DownloadUtil.download(this@BuildActivity, account, downloadUrl, build.artifactsFile.fileName)
}
}
package com.commit451.gitlab.activity;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.v4.widget.SwipeRefreshLayout;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.Toolbar;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import com.commit451.gitlab.App;
import com.commit451.gitlab.R;
import com.commit451.gitlab.adapter.DiffAdapter;
import com.commit451.gitlab.model.api.Diff;
import com.commit451.gitlab.model.api.Project;
import com.commit451.gitlab.model.api.RepositoryCommit;
import com.commit451.gitlab.rx.CustomSingleObserver;
import org.parceler.Parcels;
import java.util.List;
import butterknife.BindView;
import butterknife.ButterKnife;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.schedulers.Schedulers;
import timber.log.Timber;
/**
* Shows the lines of a commit aka the diff
*/
public class DiffActivity extends BaseActivity {
private static final String EXTRA_PROJECT = "extra_project";
private static final String EXTRA_COMMIT = "extra_commit";
public static Intent newIntent(Context context, Project project, RepositoryCommit commit) {
Intent intent = new Intent(context, DiffActivity.class);
intent.putExtra(EXTRA_PROJECT, Parcels.wrap(project));
intent.putExtra(EXTRA_COMMIT, Parcels.wrap(commit));
return intent;
}
@BindView(R.id.root)
ViewGroup root;
@BindView(R.id.toolbar)
Toolbar toolbar;
@BindView(R.id.swipe_layout)
SwipeRefreshLayout swipeRefreshLayout;
@BindView(R.id.list)
RecyclerView listDiff;
@BindView(R.id.message_text)
TextView textMessage;
DiffAdapter adapterDiff;
private Project project;
private RepositoryCommit commit;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_diff);
ButterKnife.bind(this);
project = Parcels.unwrap(getIntent().getParcelableExtra(EXTRA_PROJECT));
commit = Parcels.unwrap(getIntent().getParcelableExtra(EXTRA_COMMIT));
toolbar.setNavigationIcon(R.drawable.ic_back_24dp);
toolbar.setNavigationOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
onBackPressed();
}
});
toolbar.setTitle(commit.getShortId());
adapterDiff = new DiffAdapter(commit, new DiffAdapter.Listener() {
@Override
public void onDiffClicked(Diff diff) {
}
});
listDiff.setAdapter(adapterDiff);
listDiff.setLayoutManager(new LinearLayoutManager(this));
swipeRefreshLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
@Override
public void onRefresh() {
loadData();
}
});
loadData();
}
private void loadData() {
textMessage.setVisibility(View.GONE);
swipeRefreshLayout.post(new Runnable() {
@Override
public void run() {
if (swipeRefreshLayout != null) {
swipeRefreshLayout.setRefreshing(true);
}
}
});
App.get().getGitLab().getCommitDiff(project.getId(), commit.getId())
.compose(this.<List<Diff>>bindToLifecycle())
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new CustomSingleObserver<List<Diff>>() {
@Override
public void error(@NonNull Throwable t) {
swipeRefreshLayout.setRefreshing(false);
Timber.e(t);
textMessage.setText(R.string.connection_error);
textMessage.setVisibility(View.VISIBLE);
}
@Override
public void success(@NonNull List<Diff> diffs) {
swipeRefreshLayout.setRefreshing(false);
adapterDiff.setData(diffs);
}
});
}
}
\ No newline at end of file
package com.commit451.gitlab.activity
import android.content.Context
import android.content.Intent
import android.os.Bundle
import android.os.Parcelable
import android.support.v4.widget.SwipeRefreshLayout
import android.support.v7.widget.LinearLayoutManager
import android.support.v7.widget.RecyclerView
import android.support.v7.widget.Toolbar
import android.view.View
import android.view.ViewGroup
import android.widget.TextView
import butterknife.BindView
import butterknife.ButterKnife
import com.commit451.gitlab.App
import com.commit451.gitlab.R
import com.commit451.gitlab.adapter.DiffAdapter
import com.commit451.gitlab.model.api.Diff
import com.commit451.gitlab.model.api.Project
import com.commit451.gitlab.model.api.RepositoryCommit
import com.commit451.gitlab.rx.CustomSingleObserver
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.schedulers.Schedulers
import org.parceler.Parcels
import timber.log.Timber
/**
* Shows the lines of a commit aka the diff
*/
class DiffActivity : BaseActivity() {
companion object {
private val EXTRA_PROJECT = "extra_project"
private val EXTRA_COMMIT = "extra_commit"
fun newIntent(context: Context, project: Project, commit: RepositoryCommit): Intent {
val intent = Intent(context, DiffActivity::class.java)
intent.putExtra(EXTRA_PROJECT, Parcels.wrap(project))
intent.putExtra(EXTRA_COMMIT, Parcels.wrap(commit))
return intent
}
}
@BindView(R.id.root)
lateinit var root: ViewGroup
@BindView(R.id.toolbar)
lateinit var toolbar: Toolbar
@BindView(R.id.swipe_layout)
lateinit var swipeRefreshLayout: SwipeRefreshLayout
@BindView(R.id.list)
lateinit var listDiff: RecyclerView
@BindView(R.id.message_text)
lateinit var textMessage: TextView
lateinit var adapterDiff: DiffAdapter
lateinit var project: Project
lateinit var commit: RepositoryCommit
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_diff)
ButterKnife.bind(this)
project = Parcels.unwrap<Project>(intent.getParcelableExtra<Parcelable>(EXTRA_PROJECT))
commit = Parcels.unwrap<RepositoryCommit>(intent.getParcelableExtra<Parcelable>(EXTRA_COMMIT))
toolbar.setNavigationIcon(R.drawable.ic_back_24dp)
toolbar.setNavigationOnClickListener { onBackPressed() }
toolbar.title = commit.shortId
adapterDiff = DiffAdapter(commit, DiffAdapter.Listener { })
listDiff.adapter = adapterDiff
listDiff.layoutManager = LinearLayoutManager(this)
swipeRefreshLayout.setOnRefreshListener { loadData() }
loadData()
}
fun loadData() {
textMessage.visibility = View.GONE
swipeRefreshLayout.isRefreshing = true
App.get().gitLab.getCommitDiff(project.id, commit.id)
.compose(this.bindToLifecycle<List<Diff>>())
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(object : CustomSingleObserver<List<Diff>>() {
override fun error(t: Throwable) {
swipeRefreshLayout.isRefreshing = false
Timber.e(t)
textMessage.setText(R.string.connection_error)
textMessage.visibility = View.VISIBLE
}
override fun success(diffs: List<Diff>) {
swipeRefreshLayout.isRefreshing = false
adapterDiff.setData(diffs)
}
})
}
}
\ No newline at end of file
package com.commit451.gitlab.activity;
import android.Manifest;
import android.annotation.TargetApi;
import android.content.ActivityNotFoundException;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.net.Uri;
import android.os.Bundle;
import android.os.Environment;
import android.support.annotation.IntDef;
import android.support.annotation.NonNull;
import android.support.design.widget.Snackbar;
import android.support.v4.content.ContextCompat;
import android.support.v7.widget.Toolbar;
import android.text.Html;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.webkit.MimeTypeMap;
import android.webkit.WebView;
import com.commit451.gitlab.App;
import com.commit451.gitlab.R;
import com.commit451.gitlab.model.api.RepositoryFile;
import com.commit451.gitlab.rx.CustomSingleObserver;
import com.commit451.gitlab.rx.DecodeObservableFactory;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.nio.charset.Charset;
import butterknife.BindView;
import butterknife.ButterKnife;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.schedulers.Schedulers;
import timber.log.Timber;
public class FileActivity extends BaseActivity {
private static final int REQUEST_PERMISSION_WRITE_STORAGE = 1337;
private static final long MAX_FILE_SIZE = 1024 * 1024;
private static final String EXTRA_PROJECT_ID = "extra_project_id";
private static final String EXTRA_PATH = "extra_path";
private static final String EXTRA_REF = "extra_ref";
@Retention(RetentionPolicy.SOURCE)
@IntDef({OPTION_SAVE, OPTION_OPEN})
public @interface Option {
}
public static final int OPTION_SAVE = 0;
public static final int OPTION_OPEN = 1;
public static Intent newIntent(Context context, long projectId, String path, String ref) {
Intent intent = new Intent(context, FileActivity.class);
intent.putExtra(EXTRA_PROJECT_ID, projectId);
intent.putExtra(EXTRA_PATH, path);
intent.putExtra(EXTRA_REF, ref);
return intent;
}
@BindView(R.id.root)
ViewGroup root;
@BindView(R.id.toolbar)
Toolbar toolbar;
@BindView(R.id.file_blob)
WebView webViewFileBlob;
@BindView(R.id.progress)
View progress;
private long projectId;
private String path;
private String ref;
private RepositoryFile repositoryFile;
private String fileName;
private byte[] blob;
@Option
private int option;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_file);
ButterKnife.bind(this);
projectId = getIntent().getLongExtra(EXTRA_PROJECT_ID, -1);
path = getIntent().getStringExtra(EXTRA_PATH);
ref = getIntent().getStringExtra(EXTRA_REF);
toolbar.setNavigationIcon(R.drawable.ic_back_24dp);
toolbar.setNavigationOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
onBackPressed();
}
});
toolbar.setOnMenuItemClickListener(new Toolbar.OnMenuItemClickListener() {
@Override
public boolean onMenuItemClick(MenuItem item) {
switch (item.getItemId()) {
case R.id.action_open:
option = OPTION_OPEN;
checkAccountPermission();
return true;
case R.id.action_save:
option = OPTION_SAVE;
checkAccountPermission();
return true;
}
return false;
}
});
loadData();
}
private void loadData() {
progress.setVisibility(View.VISIBLE);
App.get().getGitLab().getFile(projectId, path, ref)
.compose(this.<RepositoryFile>bindToLifecycle())
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new CustomSingleObserver<RepositoryFile>() {
@Override
public void error(@NonNull Throwable t) {
Timber.e(t);
progress.setVisibility(View.GONE);
Snackbar.make(root, R.string.file_load_error, Snackbar.LENGTH_SHORT)
.show();
}
@Override
public void success(@NonNull RepositoryFile repositoryFile) {
progress.setVisibility(View.GONE);
bindFile(repositoryFile);
}
});
}
private void bindFile(RepositoryFile repositoryFile) {
this.repositoryFile = repositoryFile;
fileName = repositoryFile.getFileName();
toolbar.setTitle(fileName);
if (repositoryFile.getSize() > MAX_FILE_SIZE) {
Snackbar.make(root, R.string.file_too_big, Snackbar.LENGTH_SHORT)
.show();
} else {
loadBlob(repositoryFile);
}
}
private void loadBlob(RepositoryFile repositoryFile) {
DecodeObservableFactory.newDecode(repositoryFile.getContent())
.compose(this.<byte[]>bindToLifecycle())
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new CustomSingleObserver<byte[]>() {
@Override
public void error(@NonNull Throwable t) {
Snackbar.make(root, R.string.failed_to_load, Snackbar.LENGTH_SHORT)
.show();
}
@Override
public void success(@NonNull byte[] bytes) {
bindBlob(bytes);
}
});
}
private void bindBlob(byte[] blob) {
this.blob = blob;
String content;
String mimeType = null;
String extension = fileExt(fileName);
if (extension != null) {
mimeType = MimeTypeMap.getSingleton().getMimeTypeFromExtension(extension);
if (mimeType != null) {
mimeType = mimeType.toLowerCase();
}
}
if (mimeType != null && mimeType.startsWith("image/")) {
String imageURL = "data:" + mimeType + ";base64," + repositoryFile.getContent();
content = "<!DOCTYPE html>" +
"<html>" +
"<body>" +
"<img style=\"width: 100%;\" src=\"" + imageURL + "\">" +
"</body>" +
"</html>";
} else {
String text = new String(this.blob, Charset.forName("UTF-8"));
content = "<!DOCTYPE html>" +
"<html>" +
"<head>" +
"<link href=\"github.css\" rel=\"stylesheet\" />" +
"</head>" +
"<body>" +
"<pre><code>" +
Html.escapeHtml(text) +
"</code></pre>" +
"<script src=\"highlight.pack.js\"></script>" +
"<script>hljs.initHighlightingOnLoad();</script>" +
"</body>" +
"</html>";
}
webViewFileBlob.loadDataWithBaseURL("file:///android_asset/", content, "text/html", "utf8", null);
toolbar.inflateMenu(R.menu.menu_file);
}
@TargetApi(23)
private void checkAccountPermission() {
if (ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED) {
if (option == OPTION_SAVE) {
saveBlob();
} else {
openFile();
}
} else {
requestPermissions(new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, REQUEST_PERMISSION_WRITE_STORAGE);
}
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String permissions[], @NonNull int[] grantResults) {
switch (requestCode) {
case REQUEST_PERMISSION_WRITE_STORAGE: {
if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
if (option == OPTION_SAVE) {
saveBlob();
} else {
openFile();
}
}
}
}
}
private File saveBlob() {
String state = Environment.getExternalStorageState();
if (Environment.MEDIA_MOUNTED.equals(state) && blob != null) {
File targetFile = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS), fileName);
FileOutputStream outputStream = null;
try {
outputStream = new FileOutputStream(targetFile);
outputStream.write(blob);
Snackbar.make(root, getString(R.string.file_saved), Snackbar.LENGTH_SHORT)
.show();
return targetFile;
} catch (IOException e) {
Timber.e(e);
Snackbar.make(root, getString(R.string.save_error), Snackbar.LENGTH_SHORT)
.show();
} finally {
if (outputStream != null) {
try {
outputStream.close();
} catch (IOException e) {
Timber.e(e);
}
}
}
} else {
Snackbar.make(root, getString(R.string.save_error), Snackbar.LENGTH_SHORT)
.show();
}
return null;
}
private void openFile() {
File file = saveBlob();
if (file == null) {
Snackbar.make(root, getString(R.string.open_error), Snackbar.LENGTH_SHORT)
.show();
return;
}
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.setData(Uri.fromFile(file));
String extension = fileExt(file.getName());
if (extension != null) {
intent.setTypeAndNormalize(MimeTypeMap.getSingleton().getMimeTypeFromExtension(extension));
}
try {
startActivity(intent);
} catch (ActivityNotFoundException | SecurityException e) {
Timber.e(e);
Snackbar.make(root, getString(R.string.open_error), Snackbar.LENGTH_SHORT)
.show();
}
}
private static String fileExt(String filename) {
int extStart = filename.lastIndexOf(".") + 1;
if (extStart < 1) {
return null;
}
return filename.substring(extStart);
}
}
package com.commit451.gitlab.activity
import android.Manifest
import android.annotation.TargetApi
import android.content.ActivityNotFoundException
import android.content.Context
import android.content.Intent
import android.content.pm.PackageManager
import android.net.Uri
import android.os.Bundle
import android.os.Environment
import android.support.annotation.IntDef
import android.support.design.widget.Snackbar
import android.support.v4.content.ContextCompat
import android.support.v7.widget.Toolbar
import android.text.Html
import android.view.View
import android.view.ViewGroup
import android.webkit.MimeTypeMap
import android.webkit.WebView
import com.commit451.gitlab.App
import com.commit451.gitlab.R
import com.commit451.gitlab.model.api.RepositoryFile
import com.commit451.gitlab.rx.CustomSingleObserver
import com.commit451.gitlab.rx.DecodeObservableFactory
import java.io.File
import java.io.FileOutputStream
import java.io.IOException
import java.nio.charset.Charset
import butterknife.BindView
import butterknife.ButterKnife
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.schedulers.Schedulers
import timber.log.Timber
class FileActivity : BaseActivity() {
companion object {
private val REQUEST_PERMISSION_WRITE_STORAGE = 1337
private val MAX_FILE_SIZE = (1024 * 1024).toLong()
private val EXTRA_PROJECT_ID = "extra_project_id"
private val EXTRA_PATH = "extra_path"
private val EXTRA_REF = "extra_ref"
const val OPTION_SAVE = 0
const val OPTION_OPEN = 1
@Retention(AnnotationRetention.SOURCE)
@IntDef(OPTION_SAVE.toLong(), OPTION_OPEN.toLong())
annotation class Option
fun newIntent(context: Context, projectId: Long, path: String, ref: String): Intent {
val intent = Intent(context, FileActivity::class.java)
intent.putExtra(EXTRA_PROJECT_ID, projectId)
intent.putExtra(EXTRA_PATH, path)
intent.putExtra(EXTRA_REF, ref)
return intent
}
fun fileExtension(filename: String): String? {
val extStart = filename.lastIndexOf(".") + 1
if (extStart < 1) {
return null
}
return filename.substring(extStart)
}
}
@BindView(R.id.root)
lateinit var root: ViewGroup
@BindView(R.id.toolbar)
lateinit var toolbar: Toolbar
@BindView(R.id.file_blob)
lateinit var webViewFileBlob: WebView
@BindView(R.id.progress)
lateinit var progress: View
var projectId: Long = 0
var path: String? = null
var ref: String? = null
var repositoryFile: RepositoryFile? = null
var fileName: String? = null
var blob: ByteArray? = null
@Option
private var option: Int = 0
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_file)
ButterKnife.bind(this)
projectId = intent.getLongExtra(EXTRA_PROJECT_ID, -1)
path = intent.getStringExtra(EXTRA_PATH)
ref = intent.getStringExtra(EXTRA_REF)
toolbar.setNavigationIcon(R.drawable.ic_back_24dp)
toolbar.setNavigationOnClickListener { onBackPressed() }
toolbar.setOnMenuItemClickListener(Toolbar.OnMenuItemClickListener { item ->
when (item.itemId) {
R.id.action_open -> {
option = OPTION_OPEN
checkAccountPermission()
return@OnMenuItemClickListener true
}
R.id.action_save -> {
option = OPTION_SAVE
checkAccountPermission()
return@OnMenuItemClickListener true
}
}
false
})
loadData()
}
private fun loadData() {
progress.visibility = View.VISIBLE
App.get().gitLab.getFile(projectId, path, ref)
.compose(this.bindToLifecycle<RepositoryFile>())
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(object : CustomSingleObserver<RepositoryFile>() {
override fun error(t: Throwable) {
Timber.e(t)
progress.visibility = View.GONE
Snackbar.make(root, R.string.file_load_error, Snackbar.LENGTH_SHORT)
.show()
}
override fun success(repositoryFile: RepositoryFile) {
progress.visibility = View.GONE
bindFile(repositoryFile)
}
})
}
private fun bindFile(repositoryFile: RepositoryFile) {
this.repositoryFile = repositoryFile
fileName = repositoryFile.fileName
toolbar.title = fileName
if (repositoryFile.size > MAX_FILE_SIZE) {
Snackbar.make(root, R.string.file_too_big, Snackbar.LENGTH_SHORT)
.show()
} else {
loadBlob(repositoryFile)
}
}
private fun loadBlob(repositoryFile: RepositoryFile) {
DecodeObservableFactory.newDecode(repositoryFile.content)
.compose(this.bindToLifecycle<ByteArray>())
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(object : CustomSingleObserver<ByteArray>() {
override fun error(t: Throwable) {
Snackbar.make(root, R.string.failed_to_load, Snackbar.LENGTH_SHORT)
.show()
}
override fun success(bytes: ByteArray) {
bindBlob(bytes)
}
})
}
private fun bindBlob(blob: ByteArray) {
this.blob = blob
val content: String
var mimeType: String? = null
val extension = fileExtension(fileName!!)
if (extension != null) {
mimeType = MimeTypeMap.getSingleton().getMimeTypeFromExtension(extension)
if (mimeType != null) {
mimeType = mimeType.toLowerCase()
}
}
if (mimeType != null && mimeType.startsWith("image/")) {
val imageURL = "data:" + mimeType + ";base64," + repositoryFile!!.content
content = "<!DOCTYPE html>" +
"<html>" +
"<body>" +
"<img style=\"width: 100%;\" src=\"" + imageURL + "\">" +
"</body>" +
"</html>"
} else {
val text = String(this.blob!!, Charset.forName("UTF-8"))
content = "<!DOCTYPE html>" +
"<html>" +
"<head>" +
"<link href=\"github.css\" rel=\"stylesheet\" />" +
"</head>" +
"<body>" +
"<pre><code>" +
Html.escapeHtml(text) +
"</code></pre>" +
"<script src=\"highlight.pack.js\"></script>" +
"<script>hljs.initHighlightingOnLoad();</script>" +
"</body>" +
"</html>"
}
webViewFileBlob.loadDataWithBaseURL("file:///android_asset/", content, "text/html", "utf8", null)
toolbar.inflateMenu(R.menu.menu_file)
}
@TargetApi(23)
private fun checkAccountPermission() {
if (ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED) {
if (option == OPTION_SAVE) {
saveBlob()
} else {
openFile()
}
} else {
requestPermissions(arrayOf(Manifest.permission.WRITE_EXTERNAL_STORAGE), REQUEST_PERMISSION_WRITE_STORAGE)
}
}
override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<String>, grantResults: IntArray) {
when (requestCode) {
REQUEST_PERMISSION_WRITE_STORAGE -> {
if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
if (option == OPTION_SAVE) {
saveBlob()
} else {
openFile()
}
}
}
}
}
private fun saveBlob(): File? {
val state = Environment.getExternalStorageState()
if (Environment.MEDIA_MOUNTED == state && blob != null) {
val targetFile = File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS), fileName!!)
var outputStream: FileOutputStream? = null
try {
outputStream = FileOutputStream(targetFile)
outputStream.write(blob!!)
Snackbar.make(root, getString(R.string.file_saved), Snackbar.LENGTH_SHORT)
.show()
return targetFile
} catch (e: IOException) {
Timber.e(e)
Snackbar.make(root, getString(R.string.save_error), Snackbar.LENGTH_SHORT)
.show()
} finally {
if (outputStream != null) {
try {
outputStream.close()
} catch (e: IOException) {
Timber.e(e)
}
}
}
} else {
Snackbar.make(root, getString(R.string.save_error), Snackbar.LENGTH_SHORT)
.show()
}
return null
}
private fun openFile() {
val file = saveBlob()
if (file == null) {
Snackbar.make(root, getString(R.string.open_error), Snackbar.LENGTH_SHORT)
.show()
return
}
val intent = Intent(Intent.ACTION_VIEW)
intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK
intent.data = Uri.fromFile(file)
val extension = fileExtension(file.name)
if (extension != null) {
intent.setTypeAndNormalize(MimeTypeMap.getSingleton().getMimeTypeFromExtension(extension))
}
try {
startActivity(intent)
} catch (e: ActivityNotFoundException) {
Timber.e(e)
Snackbar.make(root, getString(R.string.open_error), Snackbar.LENGTH_SHORT)
.show()
} catch (e: SecurityException) {
Timber.e(e)
Snackbar.make(root, getString(R.string.open_error), Snackbar.LENGTH_SHORT).show()
}
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment