updated some api

This commit is contained in:
Mariotaku Lee 2015-05-08 18:25:58 +08:00
parent 3657295baf
commit e32e3d62a5
11 changed files with 184 additions and 102 deletions

View File

@ -26,7 +26,6 @@ import org.mariotaku.twidere.api.twitter.TwitterConverter;
import java.lang.reflect.Type; import java.lang.reflect.Type;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection;
import twitter4j.PageableResponseList; import twitter4j.PageableResponseList;
import twitter4j.Status; import twitter4j.Status;
@ -50,8 +49,8 @@ public class PageableResponseListWrapper extends TwitterResponseImpl implements
@JsonField(name = "statuses") @JsonField(name = "statuses")
ArrayList<Status> statuses; ArrayList<Status> statuses;
@JsonField(name = "user_lists") @JsonField(name = "lists")
ArrayList<Status> userLists; ArrayList<UserList> userLists;
@Override @Override
public PageableResponseList<?> getWrapped(Object extra) { public PageableResponseList<?> getWrapped(Object extra) {

View File

@ -53,7 +53,13 @@ public interface UserList extends Comparable<UserList>, TwitterResponse {
boolean isFollowing(); boolean isFollowing();
enum Mode { enum Mode {
PUBLIC, PRIVATE; PUBLIC("public"), PRIVATE("private");
private final String mode;
Mode(String mode) {
this.mode = mode;
}
public static Mode parse(String str) { public static Mode parse(String str) {
switch (str) { switch (str) {
@ -65,5 +71,8 @@ public interface UserList extends Comparable<UserList>, TwitterResponse {
throw new UnsupportedOperationException(); throw new UnsupportedOperationException();
} }
public String getMode() {
return mode;
}
} }
} }

View File

@ -34,7 +34,7 @@ public class UserListUpdate extends SimpleValueMap {
put("name", name); put("name", name);
} }
public void setPublic(boolean isPublic) { public void setMode(UserList.Mode mode) {
put("public", String.valueOf(isPublic)); put("mode", mode.getMode());
} }
} }

View File

@ -19,7 +19,10 @@
package twitter4j.api; package twitter4j.api;
import org.mariotaku.simplerestapi.http.BodyType;
import org.mariotaku.simplerestapi.method.GET; import org.mariotaku.simplerestapi.method.GET;
import org.mariotaku.simplerestapi.method.POST;
import org.mariotaku.simplerestapi.param.Body;
import org.mariotaku.simplerestapi.param.Form; import org.mariotaku.simplerestapi.param.Form;
import org.mariotaku.simplerestapi.param.Query; import org.mariotaku.simplerestapi.param.Query;
@ -36,39 +39,53 @@ import twitter4j.UserListUpdate;
* @author Joern Huxhorn - jhuxhorn at googlemail.com * @author Joern Huxhorn - jhuxhorn at googlemail.com
*/ */
public interface ListsResources { public interface ListsResources {
UserList addUserListMember(long listId, long userId) throws TwitterException; @POST("/lists/members/create.json")
@Body(BodyType.FORM)
UserList addUserListMember(@Query("list_id") long listId, @Query("user_id") long userId) throws TwitterException;
UserList addUserListMember(long listId, String userScreenName) throws TwitterException; @POST("/lists/members/create.json")
@Body(BodyType.FORM)
UserList addUserListMember(@Query("list_id") long listId, @Query("screen_name") String userScreenName) throws TwitterException;
UserList addUserListMembers(long listId, long[] userIds) throws TwitterException; @POST("/lists/members/create_all.json")
@Body(BodyType.FORM)
UserList addUserListMembers(@Form("list_id") long listId, @Form("user_id") long[] userIds) throws TwitterException;
UserList addUserListMembers(long listId, String[] screenNames) throws TwitterException; @POST("/lists/members/create_all.json")
@Body(BodyType.FORM)
UserList addUserListMembers(@Form("list_id") long listId, @Form("screen_name") String[] screenNames) throws TwitterException;
UserList createUserList(String listName, boolean isPublicList, String description) throws TwitterException; @POST("/lists/create.json")
@Body(BodyType.FORM)
UserList createUserList(@Form UserListUpdate update) throws TwitterException;
UserList createUserListSubscription(long listId) throws TwitterException; UserList createUserListSubscription(@Query("list_id") long listId) throws TwitterException;
UserList deleteUserListMember(long listId, long userId) throws TwitterException; UserList deleteUserListMember(@Query("list_id") long listId, @Query("user_id") long userId) throws TwitterException;
UserList deleteUserListMember(long listId, String screenName) throws TwitterException; UserList deleteUserListMember(@Query("list_id") long listId, String screenName) throws TwitterException;
UserList deleteUserListMembers(long listId, long[] userIds) throws TwitterException; UserList deleteUserListMembers(@Query("list_id") long listId, long[] userIds) throws TwitterException;
UserList deleteUserListMembers(long listId, String[] screenNames) throws TwitterException; UserList deleteUserListMembers(@Query("list_id") long listId, String[] screenNames) throws TwitterException;
UserList destroyUserList(long listId) throws TwitterException; UserList destroyUserList(@Query("list_id") long listId) throws TwitterException;
UserList destroyUserListSubscription(long listId) throws TwitterException; UserList destroyUserListSubscription(@Query("list_id") long listId) throws TwitterException;
PageableResponseList<User> getUserListMembers(long listId, Paging paging) throws TwitterException; @GET("/lists/members.json")
PageableResponseList<User> getUserListMembers(@Query("list_id") long listId, @Query Paging paging) throws TwitterException;
PageableResponseList<User> getUserListMembers(String slug, long ownerId, Paging paging) @GET("/lists/members.json")
PageableResponseList<User> getUserListMembers(@Query("slug") String slug, @Query("owner_id") long ownerId, @Query Paging paging)
throws TwitterException; throws TwitterException;
PageableResponseList<User> getUserListMembers(String slug, String ownerScreenName, Paging paging) @GET("/lists/members.json")
PageableResponseList<User> getUserListMembers(@Query("slug") String slug, @Query("owner_screen_name") String ownerScreenName, @Query Paging paging)
throws TwitterException; throws TwitterException;
PageableResponseList<UserList> getUserListMemberships(long cursor) throws TwitterException; @GET("/lists/memberships.json")
PageableResponseList<UserList> getUserListMemberships(@Query Paging paging) throws TwitterException;
@GET("/lists/memberships.json") @GET("/lists/memberships.json")
PageableResponseList<UserList> getUserListMemberships(@Query("user_id") long listMemberId, @Query Paging paging) throws TwitterException; PageableResponseList<UserList> getUserListMemberships(@Query("user_id") long listMemberId, @Query Paging paging) throws TwitterException;
@ -81,14 +98,18 @@ public interface ListsResources {
PageableResponseList<UserList> getUserListMemberships(@Query("screen_name") String listMemberScreenName, @Query Paging paging) PageableResponseList<UserList> getUserListMemberships(@Query("screen_name") String listMemberScreenName, @Query Paging paging)
throws TwitterException; throws TwitterException;
PageableResponseList<UserList> getUserListMemberships(String listMemberScreenName, long cursor, @GET("/lists/ownerships.json")
PageableResponseList<UserList> getUserListMemberships(@Query("screen_name") String listMemberScreenName, @Query Paging paging,
boolean filterToOwnedLists) throws TwitterException; boolean filterToOwnedLists) throws TwitterException;
PageableResponseList<UserList> getUserListOwnerships(long cursor) throws TwitterException; @GET("/lists/ownerships.json")
PageableResponseList<UserList> getUserListOwnerships(@Query Paging paging) throws TwitterException;
PageableResponseList<UserList> getUserListOwnerships(long listMemberId, long cursor) throws TwitterException; @GET("/lists/ownerships.json")
PageableResponseList<UserList> getUserListOwnerships(@Query("user_id") long listMemberId, @Query Paging paging) throws TwitterException;
PageableResponseList<UserList> getUserListOwnerships(String listMemberScreenName, long cursor) @GET("/lists/ownerships.json")
PageableResponseList<UserList> getUserListOwnerships(@Query("screen_name") String listMemberScreenName, @Query Paging paging)
throws TwitterException; throws TwitterException;
@GET("/lists/list.json") @GET("/lists/list.json")
@ -101,10 +122,10 @@ public interface ListsResources {
ResponseList<Status> getUserListStatuses(@Query("list_id") long listId, @Query Paging paging) throws TwitterException; ResponseList<Status> getUserListStatuses(@Query("list_id") long listId, @Query Paging paging) throws TwitterException;
@GET("/lists/statuses.json") @GET("/lists/statuses.json")
ResponseList<Status> getUserListStatuses(@Query("list_id") String slug, @Query("owner_id") long ownerId, @Query Paging paging) throws TwitterException; ResponseList<Status> getUserListStatuses(@Query("slug") String slug, @Query("owner_id") long ownerId, @Query Paging paging) throws TwitterException;
@GET("/lists/statuses.json") @GET("/lists/statuses.json")
ResponseList<Status> getUserListStatuses(@Query("list_id") String slug, @Query("owner_screen_name") String ownerScreenName, @Query Paging paging) ResponseList<Status> getUserListStatuses(@Query("slug") String slug, @Query("owner_screen_name") String ownerScreenName, @Query Paging paging)
throws TwitterException; throws TwitterException;
@GET("/lists/subscribers.json") @GET("/lists/subscribers.json")
@ -127,15 +148,16 @@ public interface ListsResources {
PageableResponseList<UserList> getUserListSubscriptions(@Query("user_id") long userId, long cursor) PageableResponseList<UserList> getUserListSubscriptions(@Query("user_id") long userId, long cursor)
throws TwitterException; throws TwitterException;
UserList showUserList(long listId) throws TwitterException; @GET("/lists/show.json")
UserList showUserList(@Query("list_id") long listId) throws TwitterException;
UserList showUserList(String slug, long ownerId) throws TwitterException; @GET("/lists/show.json")
UserList showUserList(@Query("slug") String slug, @Query("owner_id") long ownerId) throws TwitterException;
UserList showUserList(String slug, String ownerScreenName) throws TwitterException; @GET("/lists/show.json")
UserList showUserList(@Query("slug") String slug, @Query("owner_screen_name") String ownerScreenName) throws TwitterException;
User showUserListMembership(long listId, long userId) throws TwitterException;
User showUserListSubscription(long listId, long userId) throws TwitterException;
@POST("/lists/update.json")
@Body(BodyType.FORM)
UserList updateUserList(@Query("list_id") long listId, @Form UserListUpdate update) throws TwitterException; UserList updateUserList(@Query("list_id") long listId, @Form UserListUpdate update) throws TwitterException;
} }

View File

@ -40,9 +40,6 @@ import twitter4j.SettingsUpdate;
import twitter4j.TwitterException; import twitter4j.TwitterException;
import twitter4j.User; import twitter4j.User;
/**
* @author Joern Huxhorn - jhuxhorn at googlemail.com
*/
public interface UsersResources { public interface UsersResources {
@POST("/blocks/create.json") @POST("/blocks/create.json")

View File

@ -28,73 +28,76 @@ import android.support.annotation.NonNull;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.View; import android.view.View;
import android.widget.CheckBox; import android.widget.CheckBox;
import android.widget.EditText;
import com.rengwuxian.materialedittext.MaterialEditText;
import org.mariotaku.twidere.R; import org.mariotaku.twidere.R;
import org.mariotaku.twidere.text.validator.UserListNameValidator;
import org.mariotaku.twidere.util.AsyncTwitterWrapper; import org.mariotaku.twidere.util.AsyncTwitterWrapper;
import org.mariotaku.twidere.util.ParseUtils; import org.mariotaku.twidere.util.ParseUtils;
import org.mariotaku.twidere.util.ThemeUtils; import org.mariotaku.twidere.util.ThemeUtils;
public class CreateUserListDialogFragment extends BaseSupportDialogFragment implements DialogInterface.OnClickListener { public class CreateUserListDialogFragment extends BaseSupportDialogFragment implements DialogInterface.OnClickListener {
private EditText mEditName, mEditDescription; private MaterialEditText mEditName, mEditDescription;
private CheckBox mPublicCheckBox; private CheckBox mPublicCheckBox;
private String mName, mDescription; private String mName, mDescription;
private long mAccountId; private long mAccountId;
private long mListId; private long mListId;
private boolean mIsPublic = true; private boolean mIsPublic = true;
private AsyncTwitterWrapper mTwitterWrapper; private AsyncTwitterWrapper mTwitterWrapper;
@Override
public void onClick(final DialogInterface dialog, final int which) {
if (mAccountId <= 0) return;
switch (which) {
case DialogInterface.BUTTON_POSITIVE: {
mName = ParseUtils.parseString(mEditName.getText());
mDescription = ParseUtils.parseString(mEditDescription.getText());
mIsPublic = mPublicCheckBox.isChecked();
if (mName == null || mName.length() <= 0) return;
mTwitterWrapper.createUserListAsync(mAccountId, mName, mIsPublic, mDescription);
break;
}
}
}
@NonNull
@Override @Override
public Dialog onCreateDialog(final Bundle savedInstanceState) { public void onClick(final DialogInterface dialog, final int which) {
mTwitterWrapper = getApplication().getTwitterWrapper(); if (mAccountId <= 0) return;
final Bundle bundle = savedInstanceState == null ? getArguments() : savedInstanceState; switch (which) {
mAccountId = bundle != null ? bundle.getLong(EXTRA_ACCOUNT_ID, -1) : -1; case DialogInterface.BUTTON_POSITIVE: {
final Context wrapped = ThemeUtils.getDialogThemedContext(getActivity()); mName = ParseUtils.parseString(mEditName.getText());
final AlertDialog.Builder builder = new AlertDialog.Builder(wrapped); mDescription = ParseUtils.parseString(mEditDescription.getText());
final View view = LayoutInflater.from(wrapped).inflate(R.layout.dialog_user_list_detail_editor, null); mIsPublic = mPublicCheckBox.isChecked();
builder.setView(view); if (mName == null || mName.length() <= 0) return;
mEditName = (EditText) view.findViewById(R.id.name); mTwitterWrapper.createUserListAsync(mAccountId, mName, mIsPublic, mDescription);
mEditDescription = (EditText) view.findViewById(R.id.description); break;
mPublicCheckBox = (CheckBox) view.findViewById(R.id.is_public); }
if (mName != null) { }
mEditName.setText(mName);
}
if (mDescription != null) {
mEditDescription.setText(mDescription);
}
mPublicCheckBox.setChecked(mIsPublic);
builder.setTitle(R.string.new_user_list);
builder.setPositiveButton(android.R.string.ok, this);
builder.setNegativeButton(android.R.string.cancel, this);
return builder.create();
}
@Override }
public void onSaveInstanceState(final Bundle outState) {
outState.putLong(EXTRA_ACCOUNT_ID, mAccountId); @NonNull
outState.putLong(EXTRA_LIST_ID, mListId); @Override
outState.putString(EXTRA_LIST_NAME, mName); public Dialog onCreateDialog(final Bundle savedInstanceState) {
outState.putString(EXTRA_DESCRIPTION, mDescription); mTwitterWrapper = getApplication().getTwitterWrapper();
outState.putBoolean(EXTRA_IS_PUBLIC, mIsPublic); final Bundle bundle = savedInstanceState == null ? getArguments() : savedInstanceState;
super.onSaveInstanceState(outState); mAccountId = bundle != null ? bundle.getLong(EXTRA_ACCOUNT_ID, -1) : -1;
} final Context wrapped = ThemeUtils.getDialogThemedContext(getActivity());
final AlertDialog.Builder builder = new AlertDialog.Builder(wrapped);
final View view = LayoutInflater.from(wrapped).inflate(R.layout.dialog_user_list_detail_editor, null);
builder.setView(view);
mEditName = (MaterialEditText) view.findViewById(R.id.name);
mEditName.addValidator(new UserListNameValidator(getString(R.string.invalid_list_name)));
mEditDescription = (MaterialEditText) view.findViewById(R.id.description);
mPublicCheckBox = (CheckBox) view.findViewById(R.id.is_public);
if (mName != null) {
mEditName.setText(mName);
}
if (mDescription != null) {
mEditDescription.setText(mDescription);
}
mPublicCheckBox.setChecked(mIsPublic);
builder.setTitle(R.string.new_user_list);
builder.setPositiveButton(android.R.string.ok, this);
builder.setNegativeButton(android.R.string.cancel, this);
return builder.create();
}
@Override
public void onSaveInstanceState(final Bundle outState) {
outState.putLong(EXTRA_ACCOUNT_ID, mAccountId);
outState.putLong(EXTRA_LIST_ID, mListId);
outState.putString(EXTRA_LIST_NAME, mName);
outState.putString(EXTRA_DESCRIPTION, mDescription);
outState.putBoolean(EXTRA_IS_PUBLIC, mIsPublic);
super.onSaveInstanceState(outState);
}
} }

View File

@ -54,6 +54,8 @@ import android.view.ViewGroup;
import android.widget.CheckBox; import android.widget.CheckBox;
import android.widget.EditText; import android.widget.EditText;
import com.rengwuxian.materialedittext.MaterialEditText;
import org.mariotaku.twidere.R; import org.mariotaku.twidere.R;
import org.mariotaku.twidere.activity.iface.IThemedActivity; import org.mariotaku.twidere.activity.iface.IThemedActivity;
import org.mariotaku.twidere.activity.support.AccountSelectorActivity; import org.mariotaku.twidere.activity.support.AccountSelectorActivity;
@ -67,6 +69,7 @@ import org.mariotaku.twidere.graphic.EmptyDrawable;
import org.mariotaku.twidere.model.ParcelableUser; import org.mariotaku.twidere.model.ParcelableUser;
import org.mariotaku.twidere.model.ParcelableUserList; import org.mariotaku.twidere.model.ParcelableUserList;
import org.mariotaku.twidere.model.SingleResponse; import org.mariotaku.twidere.model.SingleResponse;
import org.mariotaku.twidere.text.validator.UserListNameValidator;
import org.mariotaku.twidere.util.AsyncTwitterWrapper; import org.mariotaku.twidere.util.AsyncTwitterWrapper;
import org.mariotaku.twidere.util.LinkCreator; import org.mariotaku.twidere.util.LinkCreator;
import org.mariotaku.twidere.util.MediaLoaderWrapper; import org.mariotaku.twidere.util.MediaLoaderWrapper;
@ -87,7 +90,6 @@ import twitter4j.UserListUpdate;
import static org.mariotaku.twidere.util.MenuUtils.setMenuItemAvailability; import static org.mariotaku.twidere.util.MenuUtils.setMenuItemAvailability;
import static org.mariotaku.twidere.util.Utils.addIntentToMenu; import static org.mariotaku.twidere.util.Utils.addIntentToMenu;
import static org.mariotaku.twidere.util.TwitterAPIUtils.getTwitterInstance;
import static org.mariotaku.twidere.util.Utils.openUserListDetails; import static org.mariotaku.twidere.util.Utils.openUserListDetails;
import static org.mariotaku.twidere.util.Utils.openUserProfile; import static org.mariotaku.twidere.util.Utils.openUserProfile;
@ -458,7 +460,7 @@ public class UserListFragment extends BaseSupportFragment implements OnClickList
public static class EditUserListDialogFragment extends BaseSupportDialogFragment implements public static class EditUserListDialogFragment extends BaseSupportDialogFragment implements
DialogInterface.OnClickListener { DialogInterface.OnClickListener {
private EditText mEditName, mEditDescription; private MaterialEditText mEditName, mEditDescription;
private CheckBox mPublicCheckBox; private CheckBox mPublicCheckBox;
private String mName, mDescription; private String mName, mDescription;
private long mAccountId; private long mAccountId;
@ -476,7 +478,7 @@ public class UserListFragment extends BaseSupportFragment implements OnClickList
mIsPublic = mPublicCheckBox.isChecked(); mIsPublic = mPublicCheckBox.isChecked();
if (mName == null || mName.length() <= 0) return; if (mName == null || mName.length() <= 0) return;
final UserListUpdate update = new UserListUpdate(); final UserListUpdate update = new UserListUpdate();
update.setPublic(mIsPublic); update.setMode(mIsPublic ? UserList.Mode.PUBLIC : UserList.Mode.PRIVATE);
update.setName(mName); update.setName(mName);
update.setDescription(mDescription); update.setDescription(mDescription);
mTwitterWrapper.updateUserListDetails(mAccountId, mListId, update); mTwitterWrapper.updateUserListDetails(mAccountId, mListId, update);
@ -500,8 +502,9 @@ public class UserListFragment extends BaseSupportFragment implements OnClickList
final AlertDialog.Builder builder = new AlertDialog.Builder(wrapped); final AlertDialog.Builder builder = new AlertDialog.Builder(wrapped);
final View view = LayoutInflater.from(wrapped).inflate(R.layout.dialog_user_list_detail_editor, null); final View view = LayoutInflater.from(wrapped).inflate(R.layout.dialog_user_list_detail_editor, null);
builder.setView(view); builder.setView(view);
mEditName = (EditText) view.findViewById(R.id.name); mEditName = (MaterialEditText) view.findViewById(R.id.name);
mEditDescription = (EditText) view.findViewById(R.id.description); mEditName.addValidator(new UserListNameValidator(getString(R.string.invalid_list_name)));
mEditDescription = (MaterialEditText) view.findViewById(R.id.description);
mPublicCheckBox = (CheckBox) view.findViewById(R.id.is_public); mPublicCheckBox = (CheckBox) view.findViewById(R.id.is_public);
if (mName != null) { if (mName != null) {
mEditName.setText(mName); mEditName.setText(mName);

View File

@ -0,0 +1,44 @@
/*
* Twidere - Twitter client for Android
*
* Copyright (C) 2012-2015 Mariotaku Lee <mariotaku.lee@gmail.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.mariotaku.twidere.text.validator;
import android.support.annotation.NonNull;
import com.rengwuxian.materialedittext.validation.METValidator;
/**
* Created by mariotaku on 15/5/8.
*/
public class UserListNameValidator extends METValidator {
public UserListNameValidator(@NonNull String errorMessage) {
super(errorMessage);
}
@Override
public boolean isValid(@NonNull CharSequence text, boolean isEmpty) {
if (isEmpty) return false;
for (int i = 0, j = text.length(); i < j; i++) {
final char ch = text.charAt(i);
if (i == 0 && !Character.isLetter(ch)) return false;
if (!Character.isLetterOrDigit(ch) && ch != '-' && ch != '_') return false;
}
return true;
}
}

View File

@ -1172,7 +1172,11 @@ public class AsyncTwitterWrapper extends TwitterWrapper {
final Twitter twitter = TwitterAPIUtils.getTwitterInstance(mContext, account_id, false); final Twitter twitter = TwitterAPIUtils.getTwitterInstance(mContext, account_id, false);
if (twitter == null || list_name == null) return SingleResponse.getInstance(); if (twitter == null || list_name == null) return SingleResponse.getInstance();
try { try {
final UserList list = twitter.createUserList(list_name, is_public, description); final UserListUpdate userListUpdate = new UserListUpdate();
userListUpdate.setName(list_name);
userListUpdate.setMode(is_public ? UserList.Mode.PUBLIC : UserList.Mode.PRIVATE);
userListUpdate.setDescription(description);
final UserList list = twitter.createUserList(userListUpdate);
return SingleResponse.getInstance(list, null); return SingleResponse.getInstance(list, null);
} catch (final TwitterException e) { } catch (final TwitterException e) {
return SingleResponse.getInstance(null, e); return SingleResponse.getInstance(null, e);

View File

@ -36,7 +36,7 @@
app:met_baseColor="?android:textColorPrimary" app:met_baseColor="?android:textColorPrimary"
app:met_floatingLabel="normal" app:met_floatingLabel="normal"
app:met_floatingLabelText="@string/name" app:met_floatingLabelText="@string/name"
app:met_maxCharacters="20" /> app:met_maxCharacters="25" />
<org.mariotaku.twidere.view.themed.BackgroundTintMaterialEditText <org.mariotaku.twidere.view.themed.BackgroundTintMaterialEditText
android:id="@+id/description" android:id="@+id/description"

View File

@ -741,4 +741,5 @@
<string name="app_restart_confirm">Twidere will restart to apply settings.</string> <string name="app_restart_confirm">Twidere will restart to apply settings.</string>
<string name="dont_restart">Don\'t restart</string> <string name="dont_restart">Don\'t restart</string>
<string name="user_list_details">List details</string> <string name="user_list_details">List details</string>
<string name="invalid_list_name">Must start with a letter and can consist only letters, numbers, \"-\", or \"_\".</string>
</resources> </resources>