From 172eb3b76f302644141af6ddabfd3736fce082c2 Mon Sep 17 00:00:00 2001 From: vanitasvitae Date: Sun, 10 May 2015 13:38:24 +0200 Subject: [PATCH] Initial commit --- app/src/main/AndroidManifest.xml | 43 ++ .../sticktoalbum/MainActivity.java | 430 ++++++++++++++++++ .../sticktoalbum/SettingsActivity.java | 38 ++ app/src/main/res/drawable/sticktoalbum.png | Bin 0 -> 1509 bytes app/src/main/res/layout/activity_main.xml | 17 + app/src/main/res/layout/save_dialog.xml | 18 + app/src/main/res/layout/settings.xml | 10 + app/src/main/res/menu/menu_main.xml | 9 + app/src/main/res/mipmap-hdpi/sticktoalbum.png | Bin 0 -> 601 bytes app/src/main/res/mipmap-mdpi/sticktoalbum.png | Bin 0 -> 446 bytes .../main/res/mipmap-xhdpi/sticktoalbum.png | Bin 0 -> 735 bytes .../main/res/mipmap-xxhdpi/sticktoalbum.png | Bin 0 -> 1076 bytes .../main/res/mipmap-xxxhdpi/sticktoalbum.png | Bin 0 -> 1509 bytes app/src/main/res/values-de/strings.xml | 17 + app/src/main/res/values-w820dp/dimens.xml | 6 + app/src/main/res/values/dimens.xml | 5 + app/src/main/res/values/strings.xml | 17 + .../res/values/strings_activity_settings.xml | 61 +++ app/src/main/res/values/styles.xml | 8 + app/src/main/sticktoalbum-web.png | Bin 0 -> 5379 bytes 20 files changed, 679 insertions(+) create mode 100644 app/src/main/AndroidManifest.xml create mode 100644 app/src/main/java/de/vanitasvitae/sticktoalbum/MainActivity.java create mode 100644 app/src/main/java/de/vanitasvitae/sticktoalbum/SettingsActivity.java create mode 100644 app/src/main/res/drawable/sticktoalbum.png create mode 100644 app/src/main/res/layout/activity_main.xml create mode 100644 app/src/main/res/layout/save_dialog.xml create mode 100644 app/src/main/res/layout/settings.xml create mode 100644 app/src/main/res/menu/menu_main.xml create mode 100644 app/src/main/res/mipmap-hdpi/sticktoalbum.png create mode 100644 app/src/main/res/mipmap-mdpi/sticktoalbum.png create mode 100644 app/src/main/res/mipmap-xhdpi/sticktoalbum.png create mode 100644 app/src/main/res/mipmap-xxhdpi/sticktoalbum.png create mode 100644 app/src/main/res/mipmap-xxxhdpi/sticktoalbum.png create mode 100644 app/src/main/res/values-de/strings.xml create mode 100644 app/src/main/res/values-w820dp/dimens.xml create mode 100644 app/src/main/res/values/dimens.xml create mode 100644 app/src/main/res/values/strings.xml create mode 100644 app/src/main/res/values/strings_activity_settings.xml create mode 100644 app/src/main/res/values/styles.xml create mode 100644 app/src/main/sticktoalbum-web.png diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml new file mode 100644 index 0000000..92b6161 --- /dev/null +++ b/app/src/main/AndroidManifest.xml @@ -0,0 +1,43 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/java/de/vanitasvitae/sticktoalbum/MainActivity.java b/app/src/main/java/de/vanitasvitae/sticktoalbum/MainActivity.java new file mode 100644 index 0000000..5f45f70 --- /dev/null +++ b/app/src/main/java/de/vanitasvitae/sticktoalbum/MainActivity.java @@ -0,0 +1,430 @@ +package de.vanitasvitae.sticktoalbum; + +import android.app.AlertDialog; +import android.content.ContentUris; +import android.content.Context; +import android.content.DialogInterface; +import android.content.Intent; +import android.content.SharedPreferences; +import android.database.Cursor; +import android.media.MediaScannerConnection; +import android.net.Uri; +import android.os.AsyncTask; +import android.os.Bundle; +import android.os.Environment; +import android.preference.PreferenceManager; +import android.provider.MediaStore; +import android.support.v7.app.ActionBarActivity; +import android.text.InputType; +import android.util.Log; +import android.view.LayoutInflater; +import android.view.View; +import android.webkit.MimeTypeMap; +import android.widget.AdapterView; +import android.widget.ArrayAdapter; +import android.widget.EditText; +import android.widget.ListView; +import android.widget.Toast; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.util.ArrayList; + +/** + * "Stick" your photos and videos into albums by moving them into new folders and updating + * Androids MediaStore. + * @author vanitas + */ +public class MainActivity extends ActionBarActivity +{ + private ArrayList sharedMedia; + private static String Tag = "stickToAlbum"; + + @Override + protected void onCreate(Bundle savedInstanceState) + { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_main); + + SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(this); + String appDirectoryPath = sharedPref.getString(SettingsActivity.KEY_PREF_APP_PATH, ""); + + if(appDirectoryPath.isEmpty()) + { + appDirectoryPath = resetAppDirectoryPath(); + } + sharedMedia = new ArrayList(); + + Intent intent = getIntent(); + String action = intent.getAction(); + String type = intent.getType(); + + Log.d(Tag, "Intent: " + action + ", " + type); + + if (Intent.ACTION_SEND.equals(action) && type != null) + { + if (type.startsWith("image/") || type.startsWith("video/")) + { + handleSendSingleFile(intent); + } + } + else if (Intent.ACTION_SEND_MULTIPLE.equals(action) && type != null) + { + handleSendMultipleFiles(intent); + } + else + { + handleStartFromHomeScreen(); + } + } + + /** + * Handle one single file being shared with the application. + * Add the files Uri to the list of files to move and open the saveDialog. + * @param intent + */ + void handleSendSingleFile(Intent intent) { + Uri imageUri = intent.getParcelableExtra(Intent.EXTRA_STREAM); + if (imageUri != null) { + sharedMedia.add(imageUri); + } + openSaveDialog(); + } + + /** + * Handle multiple files being shared with the application. + * Add the files Uris to the list of files to move and open the saveDialog. + * @param intent + */ + void handleSendMultipleFiles(Intent intent) { + ArrayList imageUris = intent.getParcelableArrayListExtra(Intent.EXTRA_STREAM); + if (imageUris != null) { + sharedMedia = imageUris; + } + openSaveDialog(); + } + + /** + * Show Dialog to inform the user about the fact, that the feature he/she wants to use is not + * implemented + */ + void handleUnimplementedFeature() + { + AlertDialog.Builder builder = new AlertDialog.Builder(this); + builder.setTitle(R.string.dialog_title_unimplemented_feature); + builder.setMessage(R.string.dialog_content_unimplemented_feature); + builder.setPositiveButton(R.string.ok, new DialogInterface.OnClickListener() + { + @Override + public void onClick(DialogInterface dialog, int which) + { + dialog.cancel(); + finish(); + } + }); + builder.show(); + } + + /** + * Open a Dialog that prompts the user to enter an album name. + * Reopens dialog, if album name is empty. + * Closes app after moving files or when canceled. + */ + private void openSaveDialog() + { + final Context context = this; + AlertDialog.Builder builder = new AlertDialog.Builder(this); + builder.setTitle(getResources().getText(R.string.dialog_title_album_name)); + + LayoutInflater inflater = this.getLayoutInflater(); + View dialogView = inflater.inflate(R.layout.save_dialog, null); + builder.setView(dialogView); + + final EditText input = (EditText) dialogView.findViewById(R.id.album_name); + input.setInputType(InputType.TYPE_CLASS_TEXT); + ListView existingAlbums = (ListView) dialogView.findViewById(R.id.album_list); + final ArrayList directoryList = getFoldersOnDirectory(getAppDirectoryPath()); + ArrayAdapter adapter = new ArrayAdapter(context, android.R.layout.simple_list_item_1, directoryList); + existingAlbums.setAdapter(adapter); + existingAlbums.setOnItemClickListener(new AdapterView.OnItemClickListener() + { + @Override + public void onItemClick(AdapterView parent, View view, int position, long id) + { + input.setText(directoryList.get(position)); + } + }); + builder.setPositiveButton(R.string.ok, new DialogInterface.OnClickListener() + { + @Override + public void onClick(DialogInterface dialog, int which) + { + String aName = input.getText().toString(); + if(!aName.isEmpty()) + { + moveFiles(aName); + finish(); + } + else + { + Toast.makeText(context, getResources().getText(R.string.toast_invalid_album_name), Toast.LENGTH_SHORT).show(); + openSaveDialog(); + } + } + }); + builder.setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() + { + @Override + public void onClick(DialogInterface dialog, int which) + { + dialog.cancel(); + finish(); + } + }); + builder.show(); + } + + /** + * Show dialog that informs the user about how to use the app. + * Close app when closed. + */ + private void handleStartFromHomeScreen() + { + final Context context = this; + AlertDialog.Builder builder = new AlertDialog.Builder(this); + builder.setTitle(getResources().getText(R.string.dialog_title_on_start_from_home_screen)); + builder.setMessage(getResources().getText(R.string.dialog_content_on_start_from_home_screen)); + builder.setPositiveButton(R.string.ok, new DialogInterface.OnClickListener() + { + @Override + public void onClick(DialogInterface dialog, int which) + { + dialog.cancel(); + finish(); + } + }); + builder.setNegativeButton(R.string.action_settings, new DialogInterface.OnClickListener() + { + @Override + public void onClick(DialogInterface dialog, int which) + { + Intent intent = new Intent(context, SettingsActivity.class); + startActivity(intent); + //handleUnimplementedFeature(); + } + }); + builder.show(); + } + + /** + * Move selected files to a new album. The album is located at appDirectoryPath/albumName + * @param albumName + */ + private void moveFiles(String albumName) + { + for(Uri u: sharedMedia) + { + String srcDest = getRealPathFromURI(this, u); + if(!moveImageFromTo(srcDest, calcTargetPath(albumName, srcDest))) + { + System.out.println("Fail: " +srcDest); + } + } + } + + /** + * Move file src to target. + * @param src + * @param target + * @return + */ + private boolean moveImageFromTo(String src, String target) + { + if(!src.equals(target)) + new LoadInitialImageData().doInBackground(src,target); + return true; + } + + private void deleteFileFromMediaStore(String path) + { + if(getMimeType(path).startsWith("image/")) + { + String[] retCol = {MediaStore.Images.Media._ID}; + Cursor cur = this.getContentResolver().query( + MediaStore.Images.Media.EXTERNAL_CONTENT_URI, + retCol, + MediaStore.MediaColumns.DATA+"='"+path+"'", null, null); + if (cur.getCount() == 0) + { + Log.e(Tag, "Could not find image "+path+". Therefore can't delete file from MediaStore"); + return; + } + cur.moveToFirst(); + int id = cur.getInt(cur.getColumnIndex(MediaStore.MediaColumns._ID)); + cur.close(); + Uri uri = ContentUris.withAppendedId(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, id); + this.getContentResolver().delete(uri, null, null); + Log.v(Tag, "Deleted image "+path+" from MediaStore as "+uri); + } + else if(getMimeType(path).startsWith("video/")) + { + String[] retCol = {MediaStore.Video.Media._ID}; + Cursor cur = this.getContentResolver().query( + MediaStore.Video.Media.EXTERNAL_CONTENT_URI, + retCol, + MediaStore.MediaColumns.DATA+"='"+path+"'",null,null); + if(cur.getCount() == 0) + { + Log.e(Tag, "Could not find video "+path+". Therefore can't delete file from MediaStore"); + return; + } + cur.moveToFirst(); + int id = cur.getInt(cur.getColumnIndex(MediaStore.MediaColumns._ID)); + cur.close(); + Uri uri = ContentUris.withAppendedId(MediaStore.Video.Media.EXTERNAL_CONTENT_URI, id); + this.getContentResolver().delete(uri, null, null); + Log.v(Tag, "Deleted video "+path+" from MediaStore as "+uri); + } + } + + private void addFileToMediaStore(String path) + { + MediaScannerConnection.scanFile( + getApplicationContext(), + new String[]{path}, + null, + new MediaScannerConnection.OnScanCompletedListener() + { + @Override + public void onScanCompleted(String path, Uri uri) + { + Log.v(Tag, "File "+path+" was scanned successfully: "+uri); + } + }); + } + + private String calcTargetPath(String albumName, String srcDest) + { + String file = getAppDirectoryPath()+albumName+srcDest.substring(srcDest.lastIndexOf("/")); + Log.v(Tag, "Path for "+srcDest+" in "+albumName+" will be "+file); + return file; + } + + public String resetAppDirectoryPath() + { + String path = Environment.getExternalStorageDirectory().getAbsolutePath()+"/Pictures/Albums/"; + Log.d(Tag, "AppDirectoryPath = "+path); + SharedPreferences.Editor prefs = PreferenceManager.getDefaultSharedPreferences(this).edit(); + prefs.putString(SettingsActivity.KEY_PREF_APP_PATH, path); + prefs.apply(); + return path; + } + + public String getAppDirectoryPath() + { + SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(this); + String appDirectoryPath = sharedPref.getString(SettingsActivity.KEY_PREF_APP_PATH, ""); + if(!appDirectoryPath.isEmpty()) return appDirectoryPath; + else + { + return resetAppDirectoryPath(); + } + } + + public ArrayList getFoldersOnDirectory(String dirPath) + { + File parent = new File(dirPath); + File[] cont = parent.listFiles(); + ArrayList subDirs = new ArrayList<>(); + if(cont != null) + { + for (File f : cont) + { + if (f.isDirectory()) subDirs.add(f.getName()); + } + } + return subDirs; + } + + public String getRealPathFromURI(Context context, Uri contentUri) + { + String[] projection = {MediaStore.Images.Media.DATA}; + Cursor cursor = context.getContentResolver().query(contentUri, projection, null, null, null); + int column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA); + cursor.moveToFirst(); + String realPath = cursor.getString(column_index); + cursor.close(); + Log.v(Tag, "Real path for file "+contentUri+" is "+realPath); + return realPath; + } + + public static String getMimeType(String url) + { + String type = null; + String extension = MimeTypeMap.getFileExtensionFromUrl(url); + if (extension != null) { + MimeTypeMap mime = MimeTypeMap.getSingleton(); + type = mime.getMimeTypeFromExtension(extension); + } + return type; + } + + /** + * String[] = {src, target} + */ + private class LoadInitialImageData extends AsyncTask + { + @Override + protected Void doInBackground(String... params) + { + InputStream in = null; + OutputStream out = null; + String src = params[0]; + String target = params[1]; + try + { + File dir = new File(src.substring(0, src.lastIndexOf("/"))); + if (!dir.exists()) + dir.mkdirs(); + in = new FileInputStream(src); + File outFile = new File(target.substring(0, target.lastIndexOf("/"))); + if (!outFile.exists()) + outFile.mkdirs(); + out = new FileOutputStream(target); + + byte[] buffer = new byte[1024]; + int read; + while ((read = in.read(buffer)) != -1) + { + out.write(buffer, 0, read); + } + in.close(); + out.flush(); + out.close(); + + addFileToMediaStore(target); + deleteFileFromMediaStore(src); + + } catch (FileNotFoundException e) + { + e.printStackTrace(); + return null; + } catch (IOException e) + { + e.printStackTrace(); + return null; + } + return null; + } + + @Override + protected void onPostExecute(Void v) + { + } + } +} diff --git a/app/src/main/java/de/vanitasvitae/sticktoalbum/SettingsActivity.java b/app/src/main/java/de/vanitasvitae/sticktoalbum/SettingsActivity.java new file mode 100644 index 0000000..0dc6db4 --- /dev/null +++ b/app/src/main/java/de/vanitasvitae/sticktoalbum/SettingsActivity.java @@ -0,0 +1,38 @@ +package de.vanitasvitae.sticktoalbum; + +import android.content.SharedPreferences; +import android.os.Bundle; +import android.os.Environment; +import android.preference.PreferenceActivity; +import android.preference.PreferenceManager; + +/** + * Created by vanitas on 10.05.15. + */ +public class SettingsActivity extends PreferenceActivity implements SharedPreferences.OnSharedPreferenceChangeListener +{ + public final static String KEY_PREF_APP_PATH = "pref_app_path"; + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + addPreferencesFromResource(R.layout.settings); + getPreferenceScreen().getSharedPreferences() + .registerOnSharedPreferenceChangeListener(this); + } + + public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, + String key) { + if (key.equals(KEY_PREF_APP_PATH)) { + SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(this); + String appDirectoryPath = sharedPref.getString(SettingsActivity.KEY_PREF_APP_PATH, ""); + if(appDirectoryPath.isEmpty()) + { + String path = Environment.getExternalStorageDirectory().getAbsolutePath()+"/Pictures/Albums/"; + SharedPreferences.Editor prefs = PreferenceManager.getDefaultSharedPreferences(this).edit(); + prefs.putString(SettingsActivity.KEY_PREF_APP_PATH, path); + prefs.apply(); + } + } + } +} \ No newline at end of file diff --git a/app/src/main/res/drawable/sticktoalbum.png b/app/src/main/res/drawable/sticktoalbum.png new file mode 100644 index 0000000000000000000000000000000000000000..a04f8a0ec5f4434847b9fb724e56317a650f895b GIT binary patch literal 1509 zcma)6dsNbQ6u(6IMC>7&hUUz(<|>@IbQ4p2WhAMUHN-SsX4uP-nXY8AYF08!F@|A@ zI@@xkS4*=6J7;xw5uCuuM! z{Cb{QjMe!Aj{BYr2AwIwB^H;Q@b{}fVx3jjy6cB>oL~99t86D9PIL3SHT9)6`y{`-6)_X-m5B$+wa_(s;QcE;V6mYCw)Nne%EzwDG0XQ{;AyDvVxQOOpUN z0?Y(30hkUj4WI=l4m=gjSV3{6cwtFgph;!LzX)%g?m({&Eu5oik|T}0#a>~cfCWH$ z9r`UbETZX4<~LO#ANucbhl7~klsskyBgV1vR#gCJxh-FtS-Dg3Dba|fgPw1qZIecy zrxgSbQVu2P66s$Ps*-`K1HP82tjP>ZekRL&ATcAFu+Esqs=|2J`_iiW8Saldrg)ND zNws-ErGecTaZoMtxz_5<*n4=zUQ2)pUskF}Y z33czo%ZKqc1||9C(7KYX07W7=L9FnW*z;u#zKK~?fv&vc&Hxe>WT~|4j4vPds(kvr zoWAnX>goU>2~aC9^?et*#acc|tU=<`Q|SB+FwNCgs0I0mLd1-i7s^4vGhzOQ!M?oG}>L41i8_zLzAL zn8M$^#@aBUuxxsQzVBaFVn4?A-#qROBbcJxyL+Z^1Dn}b5PDL&)xIm|T=SW0Ha6t? zE=yqvgf@24N$9|lIKEvA%njE+#&Z;3jgOBUBM8+N#a!XsT0@`9)*5xDGqYlp_Zb?* z{V^Zh?oOTV_qms+Y-X+YStRy`$TTYWkrA+BP97bOE^R|;dtcqH9oliRsxC2nbP>3o$$ImEwaUN$O>*9lO`(h@K~CKW0* z^z4oHG;Nhqvs#{U@ou8SmozEwokW>5_uy^->b-cw{^XXf+<8N?3rE{znmuEb4UGBL zHy5CPBA|iQSXh6bTh_= + + + diff --git a/app/src/main/res/layout/save_dialog.xml b/app/src/main/res/layout/save_dialog.xml new file mode 100644 index 0000000..248af40 --- /dev/null +++ b/app/src/main/res/layout/save_dialog.xml @@ -0,0 +1,18 @@ + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/settings.xml b/app/src/main/res/layout/settings.xml new file mode 100644 index 0000000..fe0ad10 --- /dev/null +++ b/app/src/main/res/layout/settings.xml @@ -0,0 +1,10 @@ + + + + \ No newline at end of file diff --git a/app/src/main/res/menu/menu_main.xml b/app/src/main/res/menu/menu_main.xml new file mode 100644 index 0000000..08940cc --- /dev/null +++ b/app/src/main/res/menu/menu_main.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/mipmap-hdpi/sticktoalbum.png b/app/src/main/res/mipmap-hdpi/sticktoalbum.png new file mode 100644 index 0000000000000000000000000000000000000000..cf5e1700ae8b2c1670478e57d39997a2093e4f5f GIT binary patch literal 601 zcmeAS@N?(olHy`uVBq!ia0vp^9w5xY1|&n@Zgyv2U{dgOaSW-r_4by(21}p}`v>*^ z!9f;EB6+7AJDcZBiJ2oR?!I&9jvW@ecW5k~VDfBlX^>u+h&X%K-S2598fP>A6n=ZE z!Z`QV-D_{Q%=~(+rv7X0?YT4O-aY^3Om+S}p(dw=0a~I@*SBzKD+n?K$-Ibt=DTsv zYUVAPQXOTH3&SdwTRBLlt*yH5v6$C^fk~i&fklCVkpr1o&yy0V%J6HY$vv&>cc;tO z2szwb`nhoDz2vOF{)?oG_x+#6#3-_JrLxZ&YmJ-6yt^WlE@nhlG|rHiaC%+r^5hc7 z&a!A(y#-G%7yZ1o$LG@HIadV}KmICUxOrLEM@GzGW4U9-nxm!l-(GtCT(f81*$OMu zsVtl1S9*w8{H|0l++DoA?%1N3e^a)-n|Y_c{zk(a8-Zi(bHwzNs-AwH_OP+Kdt8{b4q`E*;%ipi@Nnn z8&*{K^==D2)$QeQ@Q?D&{SM~>z1UPXK4M;bFN9U?o9W6I4*wT|1MozDQri4Cp8ZdH z_0%@)V&u7jGsq)GyQLGtYD8a6hR69 f7N>gPVg6ZaRp#_z?st=ofHx(AjSweuH>-RqAXv9duEs$xEtW zg@U6BVyJk&lv)MT5;SR&_C5GR+Y2E-lHR=w02fz?CDEnm*2OxD3h)|n-l7ClVE?i= z(mO4z83r(b0SsUO0~pYG0He?cxpIFx0fseAV;7Wj$l-8$09to}!cF@9rQQZBv#|u!-;y-6EH(r3S=V|)9_YXe)XwORx ojw$kgfB_6(00Y_-z?H)K1Z#pcM3fcU4FCWD07*qoM6N<$f}@YZXaE2J literal 0 HcmV?d00001 diff --git a/app/src/main/res/mipmap-xhdpi/sticktoalbum.png b/app/src/main/res/mipmap-xhdpi/sticktoalbum.png new file mode 100644 index 0000000000000000000000000000000000000000..6cc1020a6f44406e73955b0223244242579ecdf1 GIT binary patch literal 735 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 + StickToAlbum + + Albumnamen eingeben + Teile Fotos mit der App! + Teile Fotos (oder Videos) mit StickToAlbum, um diese in ein Album zu verschieben. + Funktion nicht verfügbar + Diese Funktion ist noch nicht fertig implementiert.\nSchau mal nach Updates :) + Bitte gebe einen Albumnamen ein! + Einstellungen + OK + Abbrechen + Neues Album + + Speicherort + Wo sollen neue Alben angelegt werden? Um zurückzusetzen, lösche diesen Wert und starte die App neu. + \ No newline at end of file diff --git a/app/src/main/res/values-w820dp/dimens.xml b/app/src/main/res/values-w820dp/dimens.xml new file mode 100644 index 0000000..63fc816 --- /dev/null +++ b/app/src/main/res/values-w820dp/dimens.xml @@ -0,0 +1,6 @@ + + + 64dp + diff --git a/app/src/main/res/values/dimens.xml b/app/src/main/res/values/dimens.xml new file mode 100644 index 0000000..7e8d605 --- /dev/null +++ b/app/src/main/res/values/dimens.xml @@ -0,0 +1,5 @@ + + + 16dp + 16dp + diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml new file mode 100644 index 0000000..793b286 --- /dev/null +++ b/app/src/main/res/values/strings.xml @@ -0,0 +1,17 @@ + + StickToAlbum + + Enter Album Name + Share Images with the app! + In order to stick photos in albums, you have to share those photos (or videos) with this app. + Feature unavailable + This feature is not implemented yet.\nCheck out updates :) + Please enter valid album name! + Settings + OK + Cancel + New Album + + Album Directory + In which directory are Albums located? Delete value and restart app to reset. + \ No newline at end of file diff --git a/app/src/main/res/values/strings_activity_settings.xml b/app/src/main/res/values/strings_activity_settings.xml new file mode 100644 index 0000000..96455b2 --- /dev/null +++ b/app/src/main/res/values/strings_activity_settings.xml @@ -0,0 +1,61 @@ + + Settings + + + + + General + + Enable social recommendations + Recommendations for people to contact + based on your message history + + + Display name + John Smith + + Add friends to messages + + Always + When possible + Never + + + 1 + 0 + -1 + + + + Data & sync + + Sync frequency + + 15 minutes + 30 minutes + 1 hour + 3 hours + 6 hours + Never + + + 15 + 30 + 60 + 180 + 360 + -1 + + + System sync settings + + + Notifications + + New message notifications + + Ringtone + Silent + + Vibrate + diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml new file mode 100644 index 0000000..173e12e --- /dev/null +++ b/app/src/main/res/values/styles.xml @@ -0,0 +1,8 @@ + + + + + + diff --git a/app/src/main/sticktoalbum-web.png b/app/src/main/sticktoalbum-web.png new file mode 100644 index 0000000000000000000000000000000000000000..c7f39212fa268b417b7035bf6e35416a9fbc87bd GIT binary patch literal 5379 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 literal 0 HcmV?d00001