Add welcome wizard slides on first start requesting permissions (#1176)
* Prepare welcome wizard related to issues https://github.com/syncthing/syncthing-android/issues/1129 https://github.com/syncthing/syncthing-android/issues/622 * Add drawables and texts * Disable scrolling the ViewPager, we have buttons for that * Add welcome wizard code Ask for storage and location permission Location permission is required to run the app Recheck storage permission on each app start, if revoked the welcome slides show again. * Review * Review - Do not quit the app when storage permission is not granted * Review - Minor string improvements
|
@ -1,83 +1,309 @@
|
|||
package com.nutomic.syncthingandroid.activities;
|
||||
|
||||
import android.Manifest;
|
||||
import android.annotation.SuppressLint;
|
||||
import android.app.Activity;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.SharedPreferences;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.graphics.Color;
|
||||
import android.Manifest;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.v4.app.ActivityCompat;
|
||||
import android.support.v4.content.ContextCompat;
|
||||
import android.support.v4.view.PagerAdapter;
|
||||
import android.support.v4.view.ViewPager;
|
||||
import android.support.v7.app.AppCompatActivity;
|
||||
import android.text.Html;
|
||||
import android.util.Log;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.View;
|
||||
import android.view.View.OnTouchListener;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.Window;
|
||||
import android.view.WindowManager;
|
||||
import android.widget.Button;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
|
||||
import com.nutomic.syncthingandroid.R;
|
||||
import com.nutomic.syncthingandroid.SyncthingApp;
|
||||
import com.nutomic.syncthingandroid.service.Constants;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
public class FirstStartActivity extends Activity implements Button.OnClickListener {
|
||||
public class FirstStartActivity extends Activity {
|
||||
|
||||
private static String TAG = "FirstStartActivity";
|
||||
private static final int REQUEST_COARSE_LOCATION = 141;
|
||||
private static final int REQUEST_WRITE_STORAGE = 142;
|
||||
private static final int SLIDE_POS_LOCATION_PERMISSION = 1;
|
||||
|
||||
private ViewPager mViewPager;
|
||||
private ViewPagerAdapter mViewPagerAdapter;
|
||||
private LinearLayout mDotsLayout;
|
||||
private TextView[] mDots;
|
||||
private int[] mLayouts;
|
||||
private Button mBackButton;
|
||||
private Button mNextButton;
|
||||
|
||||
@Inject SharedPreferences mPreferences;
|
||||
|
||||
/**
|
||||
* Handles activity behaviour depending on {@link #isFirstStart()} and {@link #haveStoragePermission()}.
|
||||
*/
|
||||
@SuppressLint("ClickableViewAccessibility")
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
((SyncthingApp) getApplication()).component().inject(this);
|
||||
|
||||
if (!isFirstStart()) {
|
||||
/**
|
||||
* Recheck storage permission. If it has been revoked after the user
|
||||
* completed the welcome slides, displays the slides again.
|
||||
*/
|
||||
if (!mPreferences.getBoolean(Constants.PREF_FIRST_START, true) &&
|
||||
haveStoragePermission()) {
|
||||
startApp();
|
||||
return;
|
||||
}
|
||||
|
||||
// Show first start UI.
|
||||
// Make notification bar transparent (API level 21+)
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||
getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_STABLE |
|
||||
View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN);
|
||||
}
|
||||
|
||||
// Show first start welcome wizard UI.
|
||||
setContentView(R.layout.activity_first_start);
|
||||
Button cont = findViewById(R.id.cont);
|
||||
cont.setOnClickListener(this);
|
||||
mViewPager = (ViewPager) findViewById(R.id.view_pager);
|
||||
mDotsLayout = (LinearLayout) findViewById(R.id.layoutDots);
|
||||
mBackButton = (Button) findViewById(R.id.btn_back);
|
||||
mNextButton = (Button) findViewById(R.id.btn_next);
|
||||
|
||||
mViewPager.setOnTouchListener(new OnTouchListener() {
|
||||
@Override
|
||||
public boolean onTouch(View v, MotionEvent event) {
|
||||
// Consume the event to prevent swiping through the slides.
|
||||
v.performClick();
|
||||
return true;
|
||||
}
|
||||
});
|
||||
|
||||
// Layouts of all welcome slides
|
||||
mLayouts = new int[]{
|
||||
R.layout.activity_firststart_slide1,
|
||||
R.layout.activity_firststart_slide2,
|
||||
R.layout.activity_firststart_slide3};
|
||||
|
||||
// Add bottom dots
|
||||
addBottomDots(0);
|
||||
|
||||
// Make notification bar transparent
|
||||
changeStatusBarColor();
|
||||
|
||||
mViewPagerAdapter = new ViewPagerAdapter();
|
||||
mViewPager.setAdapter(mViewPagerAdapter);
|
||||
mViewPager.addOnPageChangeListener(mViewPagerPageChangeListener);
|
||||
|
||||
mBackButton.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
onBtnBackClick();
|
||||
}
|
||||
});
|
||||
|
||||
mNextButton.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
onBtnNextClick();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private boolean isFirstStart() {
|
||||
return mPreferences.getBoolean("first_start", true);
|
||||
public void onBtnBackClick() {
|
||||
int current = getItem(-1);
|
||||
if (current >= 0) {
|
||||
// Move to previous slider.
|
||||
mViewPager.setCurrentItem(current);
|
||||
if (current == 0) {
|
||||
mBackButton.setVisibility(View.GONE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void startApp() {
|
||||
if (!haveStoragePermission()) {
|
||||
requestStoragePermission();
|
||||
/**
|
||||
* startApp will be called in {@link #onRequestPermissionsResult()}
|
||||
* after permission was granted.
|
||||
*/
|
||||
return;
|
||||
public void onBtnNextClick() {
|
||||
// Check if we are allowed to advance to the next slide.
|
||||
if (mViewPager.getCurrentItem() == SLIDE_POS_LOCATION_PERMISSION) {
|
||||
// As the storage permission is a prerequisite to run syncthing, refuse to continue without it.
|
||||
if (!haveStoragePermission()) {
|
||||
Toast.makeText(this, R.string.toast_write_storage_permission_required,
|
||||
Toast.LENGTH_LONG).show();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
boolean isFirstStart = isFirstStart();
|
||||
if (isFirstStart) {
|
||||
int current = getItem(+1);
|
||||
if (current < mLayouts.length) {
|
||||
// Move to next slide.
|
||||
mViewPager.setCurrentItem(current);
|
||||
mBackButton.setVisibility(View.VISIBLE);
|
||||
} else {
|
||||
// Start the app after "mNextButton" was hit on the last slide.
|
||||
Log.v(TAG, "User completed first start UI.");
|
||||
mPreferences.edit().putBoolean("first_start", false).apply();
|
||||
mPreferences.edit().putBoolean(Constants.PREF_FIRST_START, false).apply();
|
||||
startApp();
|
||||
}
|
||||
}
|
||||
|
||||
private void addBottomDots(int currentPage) {
|
||||
mDots = new TextView[mLayouts.length];
|
||||
|
||||
int[] colorsActive = getResources().getIntArray(R.array.array_dot_active);
|
||||
int[] colorsInactive = getResources().getIntArray(R.array.array_dot_inactive);
|
||||
|
||||
mDotsLayout.removeAllViews();
|
||||
for (int i = 0; i < mDots.length; i++) {
|
||||
mDots[i] = new TextView(this);
|
||||
mDots[i].setText(Html.fromHtml("•"));
|
||||
mDots[i].setTextSize(35);
|
||||
mDots[i].setTextColor(colorsInactive[currentPage]);
|
||||
mDotsLayout.addView(mDots[i]);
|
||||
}
|
||||
|
||||
// In case start_into_web_gui option is enabled, start both activities so that back
|
||||
// navigation works as expected.
|
||||
if (mDots.length > 0)
|
||||
mDots[currentPage].setTextColor(colorsActive[currentPage]);
|
||||
}
|
||||
|
||||
private int getItem(int i) {
|
||||
return mViewPager.getCurrentItem() + i;
|
||||
}
|
||||
|
||||
// ViewPager change listener
|
||||
ViewPager.OnPageChangeListener mViewPagerPageChangeListener = new ViewPager.OnPageChangeListener() {
|
||||
|
||||
@Override
|
||||
public void onPageSelected(int position) {
|
||||
addBottomDots(position);
|
||||
|
||||
// Change the next button text from next to finish on last slide.
|
||||
mNextButton.setText(getString((position == mLayouts.length - 1) ? R.string.finish : R.string.cont));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPageScrolled(int arg0, float arg1, int arg2) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPageScrollStateChanged(int arg0) {
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Making notification bar transparent
|
||||
*/
|
||||
private void changeStatusBarColor() {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||
Window window = getWindow();
|
||||
window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
|
||||
window.setStatusBarColor(Color.TRANSPARENT);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* View pager adapter
|
||||
*/
|
||||
public class ViewPagerAdapter extends PagerAdapter {
|
||||
private LayoutInflater layoutInflater;
|
||||
|
||||
public ViewPagerAdapter() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object instantiateItem(ViewGroup container, int position) {
|
||||
layoutInflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
|
||||
|
||||
View view = layoutInflater.inflate(mLayouts[position], container, false);
|
||||
|
||||
/* Slide: storage permission */
|
||||
Button btnGrantStoragePerm = (Button) view.findViewById(R.id.btnGrantStoragePerm);
|
||||
if (btnGrantStoragePerm != null) {
|
||||
btnGrantStoragePerm.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
requestStoragePermission();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/* Slide: location permission */
|
||||
Button btnGrantLocationPerm = (Button) view.findViewById(R.id.btnGrantLocationPerm);
|
||||
if (btnGrantLocationPerm != null) {
|
||||
btnGrantLocationPerm.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
requestLocationPermission();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
container.addView(view);
|
||||
return view;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getCount() {
|
||||
return mLayouts.length;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isViewFromObject(View view, Object obj) {
|
||||
return view == obj;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroyItem(ViewGroup container, int position, Object object) {
|
||||
View view = (View) object;
|
||||
container.removeView(view);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Preconditions:
|
||||
* Storage permission has been granted.
|
||||
*/
|
||||
private void startApp() {
|
||||
Boolean doInitialKeyGeneration = !Constants.getConfigFile(this).exists();
|
||||
Intent mainIntent = new Intent(this, MainActivity.class);
|
||||
mainIntent.putExtra(MainActivity.EXTRA_KEY_GENERATION_IN_PROGRESS, isFirstStart);
|
||||
Intent webIntent = new Intent(this, WebGuiActivity.class);
|
||||
if (mPreferences.getBoolean("start_into_web_gui", false)) {
|
||||
startActivities(new Intent[] {mainIntent, webIntent});
|
||||
mainIntent.putExtra(MainActivity.EXTRA_KEY_GENERATION_IN_PROGRESS, doInitialKeyGeneration);
|
||||
|
||||
/**
|
||||
* In case start_into_web_gui option is enabled, start both activities
|
||||
* so that back navigation works as expected.
|
||||
*/
|
||||
if (mPreferences.getBoolean(Constants.PREF_START_INTO_WEB_GUI, false)) {
|
||||
startActivities(new Intent[] {mainIntent, new Intent(this, WebGuiActivity.class)});
|
||||
} else {
|
||||
startActivity(mainIntent);
|
||||
}
|
||||
finish();
|
||||
}
|
||||
|
||||
/**
|
||||
* Permission check and request functions
|
||||
*/
|
||||
private void requestLocationPermission() {
|
||||
ActivityCompat.requestPermissions(this,
|
||||
new String[]{Manifest.permission.ACCESS_COARSE_LOCATION},
|
||||
REQUEST_COARSE_LOCATION);
|
||||
}
|
||||
|
||||
private boolean haveStoragePermission() {
|
||||
int permissionState = ContextCompat.checkSelfPermission(this,
|
||||
Manifest.permission.WRITE_EXTERNAL_STORAGE);
|
||||
|
@ -90,23 +316,26 @@ public class FirstStartActivity extends Activity implements Button.OnClickListen
|
|||
REQUEST_WRITE_STORAGE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
startApp();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions,
|
||||
@NonNull int[] grantResults) {
|
||||
switch (requestCode) {
|
||||
case REQUEST_COARSE_LOCATION:
|
||||
if (grantResults.length == 0 ||
|
||||
grantResults[0] != PackageManager.PERMISSION_GRANTED) {
|
||||
Log.i(TAG, "User denied ACCESS_COARSE_LOCATION permission.");
|
||||
} else {
|
||||
Toast.makeText(this, R.string.permission_granted, Toast.LENGTH_SHORT).show();
|
||||
Log.i(TAG, "User granted ACCESS_COARSE_LOCATION permission.");
|
||||
}
|
||||
break;
|
||||
case REQUEST_WRITE_STORAGE:
|
||||
if (grantResults.length == 0 ||
|
||||
grantResults[0] != PackageManager.PERMISSION_GRANTED) {
|
||||
Toast.makeText(this, R.string.toast_write_storage_permission_required,
|
||||
Toast.LENGTH_LONG).show();
|
||||
this.finish();
|
||||
Log.i(TAG, "User denied WRITE_EXTERNAL_STORAGE permission.");
|
||||
} else {
|
||||
startApp();
|
||||
Toast.makeText(this, R.string.permission_granted, Toast.LENGTH_SHORT).show();
|
||||
Log.i(TAG, "User granted WRITE_EXTERNAL_STORAGE permission.");
|
||||
}
|
||||
break;
|
||||
default:
|
||||
|
|
|
@ -10,11 +10,13 @@ public class Constants {
|
|||
|
||||
public static final String FILENAME_SYNCTHING_BINARY = "libsyncthing.so";
|
||||
|
||||
public static final String PREF_FIRST_START = "first_start";
|
||||
public static final String PREF_ALWAYS_RUN_IN_BACKGROUND = "always_run_in_background";
|
||||
public static final String PREF_SYNC_ONLY_WIFI = "sync_only_wifi";
|
||||
public static final String PREF_SYNC_ONLY_WIFI_SSIDS = "sync_only_wifi_ssids_set";
|
||||
public static final String PREF_SYNC_ONLY_CHARGING = "sync_only_charging";
|
||||
public static final String PREF_RESPECT_BATTERY_SAVING = "respect_battery_saving";
|
||||
public static final String PREF_START_INTO_WEB_GUI = "start_into_web_gui";
|
||||
public static final String PREF_USE_ROOT = "use_root";
|
||||
public static final String PREF_NOTIFICATION_TYPE = "notification_type";
|
||||
public static final String PREF_ENVIRONMENT_VARIABLES = "environment_variables";
|
||||
|
|
BIN
app/src/main/res/drawable-hdpi/ic_location.png
Normal file
After Width: | Height: | Size: 23 KiB |
BIN
app/src/main/res/drawable-hdpi/ic_storage.png
Normal file
After Width: | Height: | Size: 296 B |
BIN
app/src/main/res/drawable-hdpi/ic_syncthing_logo.png
Normal file
After Width: | Height: | Size: 6.2 KiB |
BIN
app/src/main/res/drawable-ldpi/ic_location.png
Normal file
After Width: | Height: | Size: 9.7 KiB |
BIN
app/src/main/res/drawable-ldpi/ic_storage.png
Normal file
After Width: | Height: | Size: 212 B |
BIN
app/src/main/res/drawable-ldpi/ic_syncthing_logo.png
Normal file
After Width: | Height: | Size: 2.5 KiB |
BIN
app/src/main/res/drawable-mdpi/ic_location.png
Normal file
After Width: | Height: | Size: 14 KiB |
BIN
app/src/main/res/drawable-mdpi/ic_storage.png
Normal file
After Width: | Height: | Size: 245 B |
BIN
app/src/main/res/drawable-mdpi/ic_syncthing_logo.png
Normal file
After Width: | Height: | Size: 3.7 KiB |
BIN
app/src/main/res/drawable-xhdpi/ic_location.png
Normal file
After Width: | Height: | Size: 32 KiB |
BIN
app/src/main/res/drawable-xhdpi/ic_storage.png
Normal file
After Width: | Height: | Size: 384 B |
BIN
app/src/main/res/drawable-xhdpi/ic_syncthing_logo.png
Normal file
After Width: | Height: | Size: 8.8 KiB |
BIN
app/src/main/res/drawable-xxhdpi/ic_location.png
Normal file
After Width: | Height: | Size: 52 KiB |
BIN
app/src/main/res/drawable-xxhdpi/ic_storage.png
Normal file
After Width: | Height: | Size: 538 B |
BIN
app/src/main/res/drawable-xxhdpi/ic_syncthing_logo.png
Normal file
After Width: | Height: | Size: 14 KiB |
BIN
app/src/main/res/drawable-xxxhdpi/ic_location.png
Normal file
After Width: | Height: | Size: 76 KiB |
BIN
app/src/main/res/drawable-xxxhdpi/ic_storage.png
Normal file
After Width: | Height: | Size: 703 B |
BIN
app/src/main/res/drawable-xxxhdpi/ic_syncthing_logo.png
Normal file
After Width: | Height: | Size: 19 KiB |
|
@ -1,44 +1,56 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<RelativeLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:padding="16dp"
|
||||
tools:context="com.nutomic.syncthingandroid.activities.FirstStartActivity">
|
||||
tools:context="com.nutomic.syncthingandroid.activities.FirstStartActivity"
|
||||
tools:showIn="@layout/activity_first_start">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/title"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/welcome_title"
|
||||
android:layout_centerHorizontal="true"
|
||||
android:gravity="center"
|
||||
android:textColor="@color/primary_dark"
|
||||
android:textSize="30sp"
|
||||
android:layout_margin="30dp" />
|
||||
<android.support.v4.view.ViewPager
|
||||
android:id="@+id/view_pager"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/welcome_text"
|
||||
android:layout_below="@id/title"
|
||||
android:textSize="16sp"
|
||||
android:lineSpacingExtra="5sp"
|
||||
android:layout_marginStart="30dp"
|
||||
android:layout_marginLeft="30dp"
|
||||
android:layout_marginEnd="30dp"
|
||||
android:layout_marginRight="30dp" />
|
||||
<LinearLayout
|
||||
android:id="@+id/layoutDots"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="@dimen/dots_height"
|
||||
android:layout_alignParentBottom="true"
|
||||
android:layout_marginBottom="@dimen/dots_margin_bottom"
|
||||
android:gravity="center"
|
||||
android:orientation="horizontal">
|
||||
</LinearLayout>
|
||||
|
||||
<Button
|
||||
android:id="@+id/cont"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/cont"
|
||||
android:background="?android:selectableItemBackground"
|
||||
android:textColor="@color/accent"
|
||||
android:layout_alignParentEnd="true"
|
||||
android:layout_alignParentRight="true"
|
||||
android:layout_alignParentBottom="true"/>
|
||||
<View
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="1dp"
|
||||
android:alpha=".5"
|
||||
android:layout_above="@id/layoutDots"
|
||||
android:background="@android:color/white" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/btn_back"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignParentBottom="true"
|
||||
android:layout_alignParentLeft="true"
|
||||
android:layout_alignParentStart="true"
|
||||
android:background="@null"
|
||||
android:text="@string/back"
|
||||
android:textColor="@android:color/white"
|
||||
android:visibility="gone" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/btn_next"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignParentBottom="true"
|
||||
android:layout_alignParentRight="true"
|
||||
android:layout_alignParentEnd="true"
|
||||
android:background="@null"
|
||||
android:text="@string/cont"
|
||||
android:textColor="@android:color/white" />
|
||||
|
||||
</RelativeLayout>
|
||||
|
|
51
app/src/main/res/layout/activity_firststart_slide1.xml
Normal file
|
@ -0,0 +1,51 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:background="@color/bg_screen1">
|
||||
|
||||
<LinearLayout
|
||||
android:background="@color/bg_screen1"
|
||||
android:gravity="center_horizontal"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_centerInParent="true"
|
||||
android:orientation="vertical">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/title"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/welcome_title"
|
||||
android:gravity="center"
|
||||
android:textColor="@android:color/white"
|
||||
android:textSize="30sp"
|
||||
android:layout_margin="30dp" />
|
||||
|
||||
<ImageView
|
||||
android:layout_width="@dimen/img_width_height"
|
||||
android:layout_height="@dimen/img_width_height"
|
||||
android:contentDescription="@null"
|
||||
android:src="@drawable/ic_syncthing_logo" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/introduction"
|
||||
android:textColor="@android:color/white"
|
||||
android:textSize="@dimen/slide_title"
|
||||
android:textStyle="bold" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="20dp"
|
||||
android:paddingLeft="@dimen/desc_padding"
|
||||
android:paddingRight="@dimen/desc_padding"
|
||||
android:text="@string/welcome_text"
|
||||
android:textAlignment="center"
|
||||
android:textColor="@android:color/white"
|
||||
android:textSize="@dimen/slide_desc" />
|
||||
|
||||
</LinearLayout>
|
||||
</RelativeLayout>
|
68
app/src/main/res/layout/activity_firststart_slide2.xml
Normal file
|
@ -0,0 +1,68 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:background="@color/bg_screen2">
|
||||
|
||||
<LinearLayout
|
||||
android:background="@color/bg_screen2"
|
||||
android:gravity="center_horizontal"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_centerInParent="true"
|
||||
android:orientation="vertical">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/title"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/welcome_title"
|
||||
android:gravity="center"
|
||||
android:textColor="@android:color/white"
|
||||
android:textSize="30sp"
|
||||
android:layout_margin="30dp" />
|
||||
|
||||
<ImageView
|
||||
android:layout_width="@dimen/img_width_height"
|
||||
android:layout_height="@dimen/img_width_height"
|
||||
android:contentDescription="@null"
|
||||
android:src="@drawable/ic_storage" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/btnGrantStoragePerm"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_horizontal"
|
||||
android:paddingEnd="40dp"
|
||||
android:paddingLeft="40dp"
|
||||
android:paddingRight="40dp"
|
||||
android:paddingStart="40dp"
|
||||
android:text="@string/grant_permission"
|
||||
android:contentDescription="@string/grant_permission"
|
||||
android:drawableLeft="@android:drawable/ic_menu_save"
|
||||
android:drawableStart="@android:drawable/ic_menu_save"
|
||||
android:textSize="12sp" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/storage_permission_title"
|
||||
android:textColor="@android:color/white"
|
||||
android:textSize="@dimen/slide_title"
|
||||
android:textStyle="bold" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="20dp"
|
||||
android:paddingLeft="@dimen/desc_padding"
|
||||
android:paddingRight="@dimen/desc_padding"
|
||||
android:text="@string/storage_permission_desc"
|
||||
android:textAlignment="center"
|
||||
android:textColor="@android:color/white"
|
||||
android:textSize="@dimen/slide_desc" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
|
||||
</RelativeLayout>
|
67
app/src/main/res/layout/activity_firststart_slide3.xml
Normal file
|
@ -0,0 +1,67 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:background="@color/bg_screen3">
|
||||
|
||||
<LinearLayout
|
||||
android:background="@color/bg_screen3"
|
||||
android:gravity="center_horizontal"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_centerInParent="true"
|
||||
android:orientation="vertical">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/title"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/welcome_title"
|
||||
android:gravity="center"
|
||||
android:textColor="@android:color/white"
|
||||
android:textSize="30sp"
|
||||
android:layout_margin="30dp" />
|
||||
|
||||
<ImageView
|
||||
android:layout_width="@dimen/img_width_height"
|
||||
android:layout_height="@dimen/img_width_height"
|
||||
android:contentDescription="@null"
|
||||
android:src="@drawable/ic_location" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/btnGrantLocationPerm"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_horizontal"
|
||||
android:paddingEnd="40dp"
|
||||
android:paddingLeft="40dp"
|
||||
android:paddingRight="40dp"
|
||||
android:paddingStart="40dp"
|
||||
android:text="@string/grant_permission"
|
||||
android:contentDescription="@string/grant_permission"
|
||||
android:drawableLeft="@android:drawable/ic_menu_mylocation"
|
||||
android:drawableStart="@android:drawable/ic_menu_mylocation"
|
||||
android:textSize="12sp" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/location_permission_title"
|
||||
android:textColor="@android:color/white"
|
||||
android:textSize="@dimen/slide_title"
|
||||
android:textStyle="bold" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="20dp"
|
||||
android:paddingLeft="@dimen/desc_padding"
|
||||
android:paddingRight="@dimen/desc_padding"
|
||||
android:text="@string/location_permission_desc"
|
||||
android:textAlignment="center"
|
||||
android:textColor="@android:color/white"
|
||||
android:textSize="@dimen/slide_desc" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</RelativeLayout>
|
|
@ -46,6 +46,7 @@
|
|||
android:layout_marginStart="8dp"
|
||||
android:layout_marginTop="8dp"
|
||||
android:ems="10"
|
||||
android:hint="@string/folder_label"
|
||||
android:inputType="text|textMultiLine"
|
||||
app:layout_constraintBottom_toTopOf="@+id/folders"
|
||||
app:layout_constraintHorizontal_bias="0.0"
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
android:id="@+id/commandTextView"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:hint="@string/command"
|
||||
android:ems="10"
|
||||
android:inputType="textPersonName"
|
||||
/>
|
||||
|
|
|
@ -10,4 +10,38 @@
|
|||
<color name="text_blue">#ff33b5e5</color>
|
||||
<color name="text_green">#ff99cc00</color>
|
||||
<color name="light_grey">#cccccc</color>
|
||||
|
||||
<!-- FirstStartActivity welcome wizard start -->
|
||||
<!-- Screens background color-->
|
||||
<color name="bg_screen1">#3395ff</color>
|
||||
<color name="bg_screen2">#20d2bb</color>
|
||||
<color name="bg_screen3">#c873f4</color>
|
||||
<!-- <color name="bg_screen4">#f64c73</color> -->
|
||||
|
||||
<!-- dots inactive colors -->
|
||||
<color name="dot_dark_screen1">#2278d4</color>
|
||||
<color name="dot_dark_screen2">#14a895</color>
|
||||
<color name="dot_dark_screen3">#a854d4</color>
|
||||
<!-- <color name="dot_dark_screen4">#d1395c</color> -->
|
||||
|
||||
<!-- dots active colors -->
|
||||
<color name="dot_light_screen1">#93c6fd</color>
|
||||
<color name="dot_light_screen2">#8cf9eb</color>
|
||||
<color name="dot_light_screen3">#e4b5fc</color>
|
||||
<!-- <color name="dot_light_screen4">#f98da5</color> -->
|
||||
|
||||
<array name="array_dot_active">
|
||||
<item>@color/dot_light_screen1</item>
|
||||
<item>@color/dot_light_screen2</item>
|
||||
<item>@color/dot_light_screen3</item>
|
||||
<!-- <item>@color/dot_light_screen4</item> -->
|
||||
</array>
|
||||
|
||||
<array name="array_dot_inactive">
|
||||
<item>@color/dot_dark_screen1</item>
|
||||
<item>@color/dot_dark_screen2</item>
|
||||
<item>@color/dot_dark_screen3</item>
|
||||
<!-- <item>@color/dot_dark_screen4</item> -->
|
||||
</array>
|
||||
<!-- FirstStartActivity welcome wizard end -->
|
||||
</resources>
|
||||
|
|
|
@ -2,4 +2,12 @@
|
|||
<resources>
|
||||
<dimen name="material_divider_inset">72dp</dimen>
|
||||
<dimen name="toolbar_elevation">4dp</dimen>
|
||||
|
||||
<!-- Default screen margins, per the Android Design guidelines. -->
|
||||
<dimen name="dots_height">30dp</dimen>
|
||||
<dimen name="dots_margin_bottom">20dp</dimen>
|
||||
<dimen name="img_width_height">120dp</dimen>
|
||||
<dimen name="slide_title">30sp</dimen>
|
||||
<dimen name="slide_desc">16sp</dimen>
|
||||
<dimen name="desc_padding">40dp</dimen>
|
||||
</resources>
|
||||
|
|
|
@ -11,16 +11,29 @@
|
|||
<!-- Title for dialog displayed on first start -->
|
||||
<string name="welcome_title">Welcome to Syncthing for Android</string>
|
||||
|
||||
<!-- Text for dialog displayed on first start -->
|
||||
<!-- Welcome wizard -->
|
||||
<!-- Slide 1 -->
|
||||
<string name="introduction">Introduction</string>
|
||||
<string name="welcome_text">Syncthing is an open-source file synchronization application.\n\
|
||||
To share data with other devices, you need to add their unique device IDs to the device list. Afterwards you can select which folders to share with which devices.\n\
|
||||
Please report any problems you encounter via Github.</string>
|
||||
|
||||
<string name="cont">Continue</string>
|
||||
<!-- Slide 2 -->
|
||||
<string name="storage_permission_title">Storage Permission</string>
|
||||
<string name="storage_permission_desc">Syncthing needs to access your storage to do file synchronization.</string>
|
||||
|
||||
<!-- Slide 3 -->
|
||||
<string name="location_permission_title">Location Permission</string>
|
||||
<string name="location_permission_desc">Syncthing can be configured to run on selected wifi networks. Android requires applications to have location permissions to be able look up active WiFi network name, as you can sometimes infer users location from the name of the network they are connected to. If you want to use this feature, press the button above to give the required location permissions to Syncthing. Otherwise you can skip this step.</string>
|
||||
|
||||
<!-- Generic texts used everywhere -->
|
||||
<string name="back">Back</string>
|
||||
<string name="cont">Continue</string>
|
||||
<string name="finish">Finish</string>
|
||||
<string name="generic_example">Example</string>
|
||||
<string name="generic_error">Error</string>
|
||||
<string name="grant_permission">Grant permission</string>
|
||||
<string name="permission_granted">Permission granted</string>
|
||||
|
||||
<string name="accept">Accept</string>
|
||||
|
||||
|
@ -699,7 +712,6 @@ Please report any problems you encounter via Github.</string>
|
|||
<string name="maximum_age">Maximum Age</string>
|
||||
<string name="clean_out_after">Clean out after</string>
|
||||
<string name="file_versioning">File Versioning</string>
|
||||
<string name="finish">Finish</string>
|
||||
<string name="none"> None</string>
|
||||
<string name="versions_path">Versions Path</string>
|
||||
<string name="command">Command</string>
|
||||
|
|